Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
diff -Nur support-v4-22.2.1/android/support/v4/animation/AnimatorCompatHelper.java support-v4-23.0.0/android/support/v4/animation/AnimatorCompatHelper.java
--- support-v4-22.2.1/android/support/v4/animation/AnimatorCompatHelper.java 2015-07-17 03:08:30.000000000 +0900
+++ support-v4-23.0.0/android/support/v4/animation/AnimatorCompatHelper.java 2015-06-23 08:43:44.000000000 +0900
@@ -17,6 +17,7 @@
package android.support.v4.animation;
import android.os.Build;
+import android.view.View;
abstract public class AnimatorCompatHelper {
@@ -37,4 +38,8 @@
AnimatorCompatHelper() {
}
+
+ public static void clearInterpolator(View view) {
+ IMPL.clearInterpolator(view);
+ }
}
diff -Nur support-v4-22.2.1/android/support/v4/animation/AnimatorProvider.java support-v4-23.0.0/android/support/v4/animation/AnimatorProvider.java
--- support-v4-22.2.1/android/support/v4/animation/AnimatorProvider.java 2015-07-17 03:08:30.000000000 +0900
+++ support-v4-23.0.0/android/support/v4/animation/AnimatorProvider.java 2015-06-23 08:43:44.000000000 +0900
@@ -16,6 +16,8 @@
package android.support.v4.animation;
+import android.view.View;
+
/**
* A simple interface to do things in animation pulse.
* <p>
@@ -32,4 +34,6 @@
* Animator callback interface.
*/
ValueAnimatorCompat emptyValueAnimator();
+
+ void clearInterpolator(View view);
}
diff -Nur support-v4-22.2.1/android/support/v4/animation/DonutAnimatorCompatProvider.java support-v4-23.0.0/android/support/v4/animation/DonutAnimatorCompatProvider.java
--- support-v4-22.2.1/android/support/v4/animation/DonutAnimatorCompatProvider.java 2015-07-17 03:08:30.000000000 +0900
+++ support-v4-23.0.0/android/support/v4/animation/DonutAnimatorCompatProvider.java 2015-06-23 08:43:44.000000000 +0900
@@ -148,4 +148,8 @@
return mFraction;
}
}
+
+ @Override
+ public void clearInterpolator(View view) {
+ }
}
diff -Nur support-v4-22.2.1/android/support/v4/animation/HoneycombMr1AnimatorCompatProvider.java support-v4-23.0.0/android/support/v4/animation/HoneycombMr1AnimatorCompatProvider.java
--- support-v4-22.2.1/android/support/v4/animation/HoneycombMr1AnimatorCompatProvider.java 2015-07-17 03:08:30.000000000 +0900
+++ support-v4-23.0.0/android/support/v4/animation/HoneycombMr1AnimatorCompatProvider.java 2015-06-23 08:43:44.000000000 +0900
@@ -18,6 +18,7 @@
import android.animation.Animator;
import android.animation.PropertyValuesHolder;
+import android.animation.TimeInterpolator;
import android.animation.TypeEvaluator;
import android.animation.ValueAnimator;
import android.view.View;
@@ -31,6 +32,8 @@
*/
class HoneycombMr1AnimatorCompatProvider implements AnimatorProvider {
+ private TimeInterpolator mDefaultInterpolator;
+
@Override
public ValueAnimatorCompat emptyValueAnimator() {
return new HoneycombValueAnimatorCompat(ValueAnimator.ofFloat(0f, 1f));
@@ -121,4 +124,12 @@
mWrapped.onAnimationRepeat(mValueAnimatorCompat);
}
}
+
+ @Override
+ public void clearInterpolator(View view) {
+ if (mDefaultInterpolator == null) {
+ mDefaultInterpolator = new ValueAnimator().getInterpolator();
+ }
+ view.animate().setInterpolator(mDefaultInterpolator);
+ }
}
diff -Nur support-v4-22.2.1/android/support/v4/app/ActivityCompat.java support-v4-23.0.0/android/support/v4/app/ActivityCompat.java
--- support-v4-22.2.1/android/support/v4/app/ActivityCompat.java 2015-07-17 03:08:30.000000000 +0900
+++ support-v4-23.0.0/android/support/v4/app/ActivityCompat.java 2015-08-06 08:26:24.000000000 +0900
@@ -19,15 +19,21 @@
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.PackageManager;
import android.graphics.Matrix;
import android.graphics.RectF;
+import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
import android.os.Parcelable;
+import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.content.ContextCompat;
import android.view.View;
+import java.util.Arrays;
import java.util.List;
import java.util.Map;
@@ -36,6 +42,35 @@
* introduced after API level 4 in a backwards compatible fashion.
*/
public class ActivityCompat extends ContextCompat {
+
+ /**
+ * This interface is the contract for receiving the results for permission requests.
+ */
+ public interface OnRequestPermissionsResultCallback {
+
+ /**
+ * Callback for the result from requesting permissions. This method
+ * is invoked for every call on {@link #requestPermissions(android.app.Activity,
+ * String[], int)}.
+ * <p>
+ * <strong>Note:</strong> It is possible that the permissions request interaction
+ * with the user is interrupted. In this case you will receive empty permissions
+ * and results arrays which should be treated as a cancellation.
+ * </p>
+ *
+ * @param requestCode The request code passed in {@link #requestPermissions(
+ * android.app.Activity, String[], int)}
+ * @param permissions The requested permissions. Never null.
+ * @param grantResults The grant results for the corresponding permissions
+ * which is either {@link android.content.pm.PackageManager#PERMISSION_GRANTED}
+ * or {@link android.content.pm.PackageManager#PERMISSION_DENIED}. Never null.
+ *
+ * @see #requestPermissions(android.app.Activity, String[], int)
+ */
+ public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
+ @NonNull int[] grantResults);
+ }
+
/**
* Invalidate the activity's options menu, if able.
*
@@ -163,6 +198,27 @@
}
/**
+ * Backwards compatible implementation of {@link android.app.Activity#getReferrer()
+ * Activity.getReferrer}. Uses the platform's implementation if available, otherwise
+ * only falls back to digging any explicitly specified referrer from the activity's intent.
+ */
+ public Uri getReferrer(Activity activity) {
+ if (Build.VERSION.SDK_INT >= 22) {
+ return ActivityCompat22.getReferrer(activity);
+ }
+ Intent intent = activity.getIntent();
+ Uri referrer = intent.getParcelableExtra("android.intent.extra.REFERRER");
+ if (referrer != null) {
+ return referrer;
+ }
+ String referrerName = intent.getStringExtra("android.intent.extra.REFERRER_NAME");
+ if (referrerName != null) {
+ return Uri.parse(referrerName);
+ }
+ return null;
+ }
+
+ /**
* When {@link android.app.ActivityOptions#makeSceneTransitionAnimation(Activity,
* android.view.View, String)} was used to start an Activity, <var>callback</var>
* will be called to handle shared elements on the <i>launched</i> Activity. This requires
@@ -205,6 +261,110 @@
}
}
+ /**
+ * Requests permissions to be granted to this application. These permissions
+ * must be requested in your manifest, they should not be granted to your app,
+ * and they should have protection level {@link android.content.pm.PermissionInfo
+ * #PROTECTION_DANGEROUS dangerous}, regardless whether they are declared by
+ * the platform or a third-party app.
+ * <p>
+ * Normal permissions {@link android.content.pm.PermissionInfo#PROTECTION_NORMAL}
+ * are granted at install time if requested in the manifest. Signature permissions
+ * {@link android.content.pm.PermissionInfo#PROTECTION_SIGNATURE} are granted at
+ * install time if requested in the manifest and the signature of your app matches
+ * the signature of the app declaring the permissions.
+ * </p>
+ * <p>
+ * If your app does not have the requested permissions the user will be presented
+ * with UI for accepting them. After the user has accepted or rejected the
+ * requested permissions you will receive a callback reporting whether the
+ * permissions were granted or not. Your activity has to implement {@link
+ * android.support.v4.app.ActivityCompat.OnRequestPermissionsResultCallback}
+ * and the results of permission requests will be delivered to its {@link
+ * android.support.v4.app.ActivityCompat.OnRequestPermissionsResultCallback#onRequestPermissionsResult(
+ * int, String[], int[])} method.
+ * </p>
+ * <p>
+ * Note that requesting a permission does not guarantee it will be granted and
+ * your app should be able to run without having this permission.
+ * </p>
+ * <p>
+ * This method may start an activity allowing the user to choose which permissions
+ * to grant and which to reject. Hence, you should be prepared that your activity
+ * may be paused and resumed. Further, granting some permissions may require
+ * a restart of you application. In such a case, the system will recreate the
+ * activity stack before delivering the result to your onRequestPermissionsResult(
+ * int, String[], int[]).
+ * </p>
+ * <p>
+ * When checking whether you have a permission you should use {@link
+ * #checkSelfPermission(android.content.Context, String)}.
+ * </p>
+ *
+ * @param activity The target activity.
+ * @param permissions The requested permissions.
+ * @param requestCode Application specific request code to match with a result
+ * reported to {@link OnRequestPermissionsResultCallback#onRequestPermissionsResult(
+ * int, String[], int[])}.
+ *
+ * @see #checkSelfPermission(android.content.Context, String)
+ * @see #shouldShowRequestPermissionRationale(android.app.Activity, String)
+ */
+ public static void requestPermissions(final @NonNull Activity activity,
+ final @NonNull String[] permissions, final int requestCode) {
+ if (Build.VERSION.SDK_INT >= 23) {
+ ActivityCompatApi23.requestPermissions(activity, permissions, requestCode);
+ } else if (activity instanceof OnRequestPermissionsResultCallback) {
+ Handler handler = new Handler(Looper.getMainLooper());
+ handler.post(new Runnable() {
+ @Override
+ public void run() {
+ final int[] grantResults = new int[permissions.length];
+
+ PackageManager packageManager = activity.getPackageManager();
+ String packageName = activity.getPackageName();
+
+ final int permissionCount = permissions.length;
+ for (int i = 0; i < permissionCount; i++) {
+ grantResults[i] = packageManager.checkPermission(
+ permissions[i], packageName);
+ }
+
+ ((OnRequestPermissionsResultCallback) activity).onRequestPermissionsResult(
+ requestCode, permissions, grantResults);
+ }
+ });
+ }
+ }
+
+ /**
+ * Gets whether you should show UI with rationale for requesting a permission.
+ * You should do this only if you do not have the permission and the context in
+ * which the permission is requested does not clearly communicate to the user
+ * what would be the benefit from granting this permission.
+ * <p>
+ * For example, if you write a camera app, requesting the camera permission
+ * would be expected by the user and no rationale for why it is requested is
+ * needed. If however, the app needs location for tagging photos then a non-tech
+ * savvy user may wonder how location is related to taking photos. In this case
+ * you may choose to show UI with rationale of requesting this permission.
+ * </p>
+ *
+ * @param activity The target activity.
+ * @param permission A permission your app wants to request.
+ * @return Whether you can show permission rationale UI.
+ *
+ * @see #checkSelfPermission(android.content.Context, String)
+ * @see #requestPermissions(android.app.Activity, String[], int)
+ */
+ public static boolean shouldShowRequestPermissionRationale(@NonNull Activity activity,
+ @NonNull String permission) {
+ if (Build.VERSION.SDK_INT >= 23) {
+ return ActivityCompatApi23.shouldShowRequestPermissionRationale(activity, permission);
+ }
+ return false;
+ }
+
private static ActivityCompat21.SharedElementCallback21 createCallback(
SharedElementCallback callback) {
ActivityCompat21.SharedElementCallback21 newCallback = null;
diff -Nur support-v4-22.2.1/android/support/v4/app/ActivityCompat22.java support-v4-23.0.0/android/support/v4/app/ActivityCompat22.java
--- support-v4-22.2.1/android/support/v4/app/ActivityCompat22.java 1970-01-01 09:00:00.000000000 +0900
+++ support-v4-23.0.0/android/support/v4/app/ActivityCompat22.java 2015-06-23 08:43:44.000000000 +0900
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v4.app;
+
+import android.app.Activity;
+import android.net.Uri;
+
+class ActivityCompat22 {
+ public static Uri getReferrer(Activity activity) {
+ return activity.getReferrer();
+ }
+}
diff -Nur support-v4-22.2.1/android/support/v4/app/ActivityCompat23.java support-v4-23.0.0/android/support/v4/app/ActivityCompat23.java
--- support-v4-22.2.1/android/support/v4/app/ActivityCompat23.java 1970-01-01 09:00:00.000000000 +0900
+++ support-v4-23.0.0/android/support/v4/app/ActivityCompat23.java 2015-06-23 08:43:44.000000000 +0900
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v4.app;
+
+import android.app.Activity;
+
+class ActivityCompatApi23 {
+ public interface RequestPermissionsRequestCodeValidator {
+ public void validateRequestPermissionsRequestCode(int requestCode);
+ }
+
+ public static void requestPermissions(Activity activity, String[] permissions,
+ int requestCode) {
+ if (activity instanceof RequestPermissionsRequestCodeValidator) {
+ ((RequestPermissionsRequestCodeValidator) activity)
+ .validateRequestPermissionsRequestCode(requestCode);
+ }
+ activity.requestPermissions(permissions, requestCode);
+ }
+
+ public static boolean shouldShowRequestPermissionRationale(Activity activity,
+ String permission) {
+ return activity.shouldShowRequestPermissionRationale(permission);
+ }
+}
diff -Nur support-v4-22.2.1/android/support/v4/app/AppOpsManagerCompat.java support-v4-23.0.0/android/support/v4/app/AppOpsManagerCompat.java
--- support-v4-22.2.1/android/support/v4/app/AppOpsManagerCompat.java 1970-01-01 09:00:00.000000000 +0900
+++ support-v4-23.0.0/android/support/v4/app/AppOpsManagerCompat.java 2015-07-08 08:46:10.000000000 +0900
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v4.app;
+
+import android.content.Context;
+import android.os.Build;
+import android.support.annotation.NonNull;
+
+/**
+ * Helper for accessing features in android.app.AppOpsManager
+ * introduced after API level 4 in a backwards compatible fashion.
+ */
+public class AppOpsManagerCompat {
+
+ /**
+ * Result from {@link #noteOp}: the given caller is allowed to
+ * perform the given operation.
+ */
+ public static final int MODE_ALLOWED = 0;
+
+ /**
+ * Result from {@link #noteOp}: the given caller is not allowed to perform
+ * the given operation, and this attempt should <em>silently fail</em> (it
+ * should not cause the app to crash).
+ */
+ public static final int MODE_IGNORED = 1;
+
+ /**
+ * Result from {@link #noteOp}: the given caller should use its default
+ * security check. This mode is not normally used; it should only be used
+ * with appop permissions, and callers must explicitly check for it and
+ * deal with it.
+ */
+ public static final int MODE_DEFAULT = 3;
+
+ private static class AppOpsManagerImpl {
+ public String permissionToOp(String permission) {
+ return null;
+ }
+
+ public int noteOp(Context context, String op, int uid, String packageName) {
+ return MODE_IGNORED;
+ }
+
+ public int noteProxyOp(Context context, String op, String proxiedPackageName) {
+ return MODE_IGNORED;
+ }
+ }
+
+ private static class AppOpsManager23 extends AppOpsManagerImpl {
+ @Override
+ public String permissionToOp(String permission) {
+ return AppOpsManagerCompat23.permissionToOp(permission);
+ }
+
+ @Override
+ public int noteOp(Context context, String op, int uid, String packageName) {
+ return AppOpsManagerCompat23.noteOp(context, op, uid, packageName);
+ }
+
+ @Override
+ public int noteProxyOp(Context context, String op, String proxiedPackageName) {
+ return AppOpsManagerCompat23.noteProxyOp(context, op, proxiedPackageName);
+ }
+ }
+
+ private static final AppOpsManagerImpl IMPL;
+ static {
+ if (Build.VERSION.SDK_INT >= 23) {
+ IMPL = new AppOpsManager23();
+ } else {
+ IMPL = new AppOpsManagerImpl();
+ }
+ }
+
+ /**
+ * Gets the app op name associated with a given permission.
+ *
+ * @param permission The permission.
+ * @return The app op associated with the permission or null.
+ */
+ public static String permissionToOp(@NonNull String permission) {
+ return IMPL.permissionToOp(permission);
+ }
+
+ /**
+ * Make note of an application performing an operation. Note that you must pass
+ * in both the uid and name of the application to be checked; this function will verify
+ * that these two match, and if not, return {@link #MODE_IGNORED}. If this call
+ * succeeds, the last execution time of the operation for this app will be updated to
+ * the current time.
+ * @param context Your context.
+ * @param op The operation to note. One of the OPSTR_* constants.
+ * @param uid The user id of the application attempting to perform the operation.
+ * @param packageName The name of the application attempting to perform the operation.
+ * @return Returns {@link #MODE_ALLOWED} if the operation is allowed, or
+ * {@link #MODE_IGNORED} if it is not allowed and should be silently ignored (without
+ * causing the app to crash).
+ * @throws SecurityException If the app has been configured to crash on this op.
+ */
+ public static int noteOp(@NonNull Context context, @NonNull String op, int uid,
+ @NonNull String packageName) {
+ return IMPL.noteOp(context, op, uid, packageName);
+ }
+
+ /**
+ * Make note of an application performing an operation on behalf of another
+ * application when handling an IPC. Note that you must pass the package name
+ * of the application that is being proxied while its UID will be inferred from
+ * the IPC state; this function will verify that the calling uid and proxied
+ * package name match, and if not, return {@link #MODE_IGNORED}. If this call
+ * succeeds, the last execution time of the operation for the proxied app and
+ * your app will be updated to the current time.
+ * @param context Your context.
+ * @param op The operation to note. One of the OPSTR_* constants.
+ * @param proxiedPackageName The name of the application calling into the proxy application.
+ * @return Returns {@link #MODE_ALLOWED} if the operation is allowed, or
+ * {@link #MODE_IGNORED} if it is not allowed and should be silently ignored (without
+ * causing the app to crash).
+ * @throws SecurityException If the app has been configured to crash on this op.
+ */
+ public static int noteProxyOp(@NonNull Context context, @NonNull String op,
+ @NonNull String proxiedPackageName) {
+ return IMPL.noteProxyOp(context, op, proxiedPackageName);
+ }
+}
diff -Nur support-v4-22.2.1/android/support/v4/app/AppOpsManagerCompat23.java support-v4-23.0.0/android/support/v4/app/AppOpsManagerCompat23.java
--- support-v4-22.2.1/android/support/v4/app/AppOpsManagerCompat23.java 1970-01-01 09:00:00.000000000 +0900
+++ support-v4-23.0.0/android/support/v4/app/AppOpsManagerCompat23.java 2015-07-08 08:46:10.000000000 +0900
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v4.app;
+
+import android.app.AppOpsManager;
+import android.content.Context;
+
+/**
+ * AppOpsManager implementations for API 23.
+ */
+public class AppOpsManagerCompat23 {
+ public static String permissionToOp(String permission) {
+ return AppOpsManager.permissionToOp(permission);
+ }
+
+ public static int noteOp(Context context, String op, int uid, String packageName) {
+ AppOpsManager appOpsManager = context.getSystemService(AppOpsManager.class);
+ return appOpsManager.noteOp(op, uid, packageName);
+ }
+
+ public static int noteProxyOp(Context context, String op, String proxiedPackageName) {
+ AppOpsManager appOpsManager = context.getSystemService(AppOpsManager.class);
+ return appOpsManager.noteProxyOp(op, proxiedPackageName);
+ }
+}
diff -Nur support-v4-22.2.1/android/support/v4/app/BackStackRecord.java support-v4-23.0.0/android/support/v4/app/BackStackRecord.java
--- support-v4-22.2.1/android/support/v4/app/BackStackRecord.java 2015-07-17 03:08:30.000000000 +0900
+++ support-v4-23.0.0/android/support/v4/app/BackStackRecord.java 2015-07-02 08:14:40.000000000 +0900
@@ -16,13 +16,11 @@
package android.support.v4.app;
-import android.graphics.Rect;
import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
-import android.support.v4.util.LogWriter;
-import android.support.v4.util.Pair;
import android.support.v4.util.ArrayMap;
+import android.support.v4.util.LogWriter;
import android.text.TextUtils;
import android.util.Log;
import android.util.SparseArray;
@@ -33,7 +31,6 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
-import java.util.Collection;
final class BackStackState implements Parcelable {
final int[] mOps;
@@ -48,7 +45,7 @@
final ArrayList<String> mSharedElementSourceNames;
final ArrayList<String> mSharedElementTargetNames;
- public BackStackState(FragmentManagerImpl fm, BackStackRecord bse) {
+ public BackStackState(BackStackRecord bse) {
int numRemoved = 0;
BackStackRecord.Op op = bse.mHead;
while (op != null) {
@@ -371,14 +368,14 @@
public CharSequence getBreadCrumbTitle() {
if (mBreadCrumbTitleRes != 0) {
- return mManager.mActivity.getText(mBreadCrumbTitleRes);
+ return mManager.mHost.getContext().getText(mBreadCrumbTitleRes);
}
return mBreadCrumbTitleText;
}
public CharSequence getBreadCrumbShortTitle() {
if (mBreadCrumbShortTitleRes != 0) {
- return mManager.mActivity.getText(mBreadCrumbShortTitleRes);
+ return mManager.mHost.getContext().getText(mBreadCrumbShortTitleRes);
}
return mBreadCrumbShortTitleText;
}
@@ -675,12 +672,13 @@
} break;
case OP_REPLACE: {
Fragment f = op.fragment;
+ int containerId = f.mContainerId;
if (mManager.mAdded != null) {
for (int i=0; i<mManager.mAdded.size(); i++) {
Fragment old = mManager.mAdded.get(i);
if (FragmentManagerImpl.DEBUG) Log.v(TAG,
"OP_REPLACE: adding=" + f + " old=" + old);
- if (f == null || old.mContainerId == f.mContainerId) {
+ if (old.mContainerId == containerId) {
if (old == f) {
op.fragment = f = null;
} else {
@@ -774,7 +772,7 @@
*/
private void calculateFragments(SparseArray<Fragment> firstOutFragments,
SparseArray<Fragment> lastInFragments) {
- if (!mManager.mContainer.hasView()) {
+ if (!mManager.mContainer.onHasView()) {
return; // nothing to see, so no transitions
}
Op op = mHead;
@@ -832,7 +830,7 @@
*/
public void calculateBackFragments(SparseArray<Fragment> firstOutFragments,
SparseArray<Fragment> lastInFragments) {
- if (!mManager.mContainer.hasView()) {
+ if (!mManager.mContainer.onHasView()) {
return; // nothing to see, so no transitions
}
Op op = mHead;
@@ -1023,7 +1021,7 @@
// 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.
- state.nonExistentView = new View(mManager.mActivity);
+ state.nonExistentView = new View(mManager.mHost.getContext());
boolean anyTransitionStarted = false;
// Go over all leaving fragments.
@@ -1073,7 +1071,7 @@
if (inFragment == null || outFragment == null) {
return null;
}
- return FragmentTransitionCompat21.cloneTransition(isBack ?
+ return FragmentTransitionCompat21.wrapSharedElementTransition(isBack ?
outFragment.getSharedElementReturnTransition() :
inFragment.getSharedElementEnterTransition());
}
@@ -1131,7 +1129,7 @@
*/
private boolean configureTransitions(int containerId, TransitionState state, boolean isBack,
SparseArray<Fragment> firstOutFragments, SparseArray<Fragment> lastInFragments) {
- ViewGroup sceneRoot = (ViewGroup) mManager.mContainer.findViewById(containerId);
+ ViewGroup sceneRoot = (ViewGroup) mManager.mContainer.onFindViewById(containerId);
if (sceneRoot == null) {
return false;
}
@@ -1142,27 +1140,31 @@
Object sharedElementTransition = getSharedElementTransition(inFragment, outFragment,
isBack);
Object exitTransition = getExitTransition(outFragment, isBack);
- if (enterTransition == null && sharedElementTransition == null &&
- exitTransition == null) {
- return false; // no transitions!
- }
ArrayMap<String, View> namedViews = null;
ArrayList<View> sharedElementTargets = new ArrayList<View>();
if (sharedElementTransition != null) {
namedViews = remapSharedElements(state, outFragment, isBack);
- sharedElementTargets.add(state.nonExistentView);
- sharedElementTargets.addAll(namedViews.values());
-
- // Notify the start of the transition.
- SharedElementCallback callback = isBack ?
- outFragment.mEnterTransitionCallback :
- inFragment.mEnterTransitionCallback;
- if (callback != null) {
- ArrayList<String> names = new ArrayList<String>(namedViews.keySet());
- ArrayList<View> views = new ArrayList<View>(namedViews.values());
- callback.onSharedElementStart(names, views, null);
+ if (namedViews.isEmpty()) {
+ sharedElementTransition = null;
+ namedViews = null;
+ } else {
+ // Notify the start of the transition.
+ SharedElementCallback callback = isBack ?
+ outFragment.mEnterTransitionCallback :
+ inFragment.mEnterTransitionCallback;
+ if (callback != null) {
+ ArrayList<String> names = new ArrayList<String>(namedViews.keySet());
+ ArrayList<View> views = new ArrayList<View>(namedViews.values());
+ callback.onSharedElementStart(names, views, null);
+ }
+ prepareSharedElementTransition(state, sceneRoot, sharedElementTransition,
+ inFragment, outFragment, isBack, sharedElementTargets);
}
}
+ if (enterTransition == null && sharedElementTransition == null &&
+ exitTransition == null) {
+ return false; // no transitions!
+ }
ArrayList<View> exitingViews = new ArrayList<View>();
exitTransition = captureExitingViews(exitTransition, outFragment, exitingViews,
@@ -1190,16 +1192,14 @@
}
};
- if (sharedElementTransition != null) {
- prepareSharedElementTransition(state, sceneRoot, sharedElementTransition,
- inFragment, outFragment, isBack, sharedElementTargets);
- }
-
ArrayList<View> enteringViews = new ArrayList<View>();
ArrayMap<String, View> renamedViews = new ArrayMap<String, View>();
- boolean allowOverlap = isBack ? inFragment.getAllowReturnTransitionOverlap() :
- inFragment.getAllowEnterTransitionOverlap();
+ boolean allowOverlap = true;
+ if (inFragment != null) {
+ allowOverlap = isBack ? inFragment.getAllowReturnTransitionOverlap() :
+ inFragment.getAllowEnterTransitionOverlap();
+ }
Object transition = FragmentTransitionCompat21.mergeTransitions(enterTransition,
exitTransition, sharedElementTransition, allowOverlap);
@@ -1207,7 +1207,7 @@
FragmentTransitionCompat21.addTransitionTargets(enterTransition,
sharedElementTransition, sceneRoot, viewRetriever, state.nonExistentView,
state.enteringEpicenterView, state.nameOverrides, enteringViews,
- renamedViews, sharedElementTargets);
+ namedViews, renamedViews, sharedElementTargets);
excludeHiddenFragmentsAfterEnter(sceneRoot, state, containerId, transition);
// We want to exclude hidden views later, so we need a non-null list in the
@@ -1243,10 +1243,8 @@
ArrayMap<String, View> namedViews = mapSharedElementsIn(
state, isBack, inFragment);
- sharedElementTargets.add(state.nonExistentView);
- sharedElementTargets.addAll(namedViews.values());
- FragmentTransitionCompat21.addTargets(sharedElementTransition,
- sharedElementTargets);
+ FragmentTransitionCompat21.setSharedElementTargets(sharedElementTransition,
+ state.nonExistentView, namedViews, sharedElementTargets);
setEpicenterIn(namedViews, state);
@@ -1392,7 +1390,7 @@
private static void setNameOverride(ArrayMap<String, String> overrides,
String source, String target) {
- if (source != null && target != null && !source.equals(target)) {
+ if (source != null && target != null) {
for (int index = 0; index < overrides.size(); index++) {
if (source.equals(overrides.valueAt(index))) {
overrides.setValueAt(index, target);
diff -Nur support-v4-22.2.1/android/support/v4/app/BaseFragmentActivityDonut.java support-v4-23.0.0/android/support/v4/app/BaseFragmentActivityDonut.java
--- support-v4-22.2.1/android/support/v4/app/BaseFragmentActivityDonut.java 1970-01-01 09:00:00.000000000 +0900
+++ support-v4-23.0.0/android/support/v4/app/BaseFragmentActivityDonut.java 2015-06-23 08:43:44.000000000 +0900
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v4.app;
+
+import android.app.Activity;
+import android.content.Context;
+import android.os.Build;
+import android.os.Bundle;
+import android.util.AttributeSet;
+import android.view.View;
+
+/**
+ * Base class for {@code FragmentActivity} to be able to use Donut APIs.
+ */
+abstract class BaseFragmentActivityDonut extends Activity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ if (Build.VERSION.SDK_INT < 11 && getLayoutInflater().getFactory() == null) {
+ // On pre-HC devices we need to manually install ourselves as a Factory.
+ // On HC and above, we are automatically installed as a private factory
+ getLayoutInflater().setFactory(this);
+ }
+
+ super.onCreate(savedInstanceState);
+ }
+
+ @Override
+ public View onCreateView(String name, Context context, AttributeSet attrs) {
+ final View v = dispatchFragmentsOnCreateView(null, name, context, attrs);
+ if (v == null) {
+ return super.onCreateView(name, context, attrs);
+ }
+ return v;
+ }
+
+ abstract View dispatchFragmentsOnCreateView(View parent, String name,
+ Context context, AttributeSet attrs);
+
+}
diff -Nur support-v4-22.2.1/android/support/v4/app/BaseFragmentActivityHoneycomb.java support-v4-23.0.0/android/support/v4/app/BaseFragmentActivityHoneycomb.java
--- support-v4-22.2.1/android/support/v4/app/BaseFragmentActivityHoneycomb.java 1970-01-01 09:00:00.000000000 +0900
+++ support-v4-23.0.0/android/support/v4/app/BaseFragmentActivityHoneycomb.java 2015-06-23 08:43:44.000000000 +0900
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v4.app;
+
+import android.content.Context;
+import android.os.Build;
+import android.util.AttributeSet;
+import android.view.View;
+
+/**
+ * Base class for {@code FragmentActivity} to be able to use v11 APIs.
+ */
+abstract class BaseFragmentActivityHoneycomb extends BaseFragmentActivityDonut {
+
+ @Override
+ public View onCreateView(View parent, String name, Context context, AttributeSet attrs) {
+ final View v = dispatchFragmentsOnCreateView(parent, name, context, attrs);
+ if (v == null && Build.VERSION.SDK_INT >= 11) {
+ // If we're running on HC or above, let the super have a go
+ return super.onCreateView(parent, name, context, attrs);
+ }
+ return v;
+ }
+
+}
diff -Nur support-v4-22.2.1/android/support/v4/app/DialogFragment.java support-v4-23.0.0/android/support/v4/app/DialogFragment.java
--- support-v4-22.2.1/android/support/v4/app/DialogFragment.java 2015-07-17 03:08:30.000000000 +0900
+++ support-v4-23.0.0/android/support/v4/app/DialogFragment.java 2015-06-23 08:43:44.000000000 +0900
@@ -306,22 +306,29 @@
}
mDialog = onCreateDialog(savedInstanceState);
- switch (mStyle) {
+
+ if (mDialog != null) {
+ setupDialog(mDialog, mStyle);
+
+ return (LayoutInflater) mDialog.getContext().getSystemService(
+ Context.LAYOUT_INFLATER_SERVICE);
+ }
+ return (LayoutInflater) mHost.getContext().getSystemService(
+ Context.LAYOUT_INFLATER_SERVICE);
+ }
+
+ /** @hide */
+ public void setupDialog(Dialog dialog, int style) {
+ switch (style) {
case STYLE_NO_INPUT:
- mDialog.getWindow().addFlags(
+ dialog.getWindow().addFlags(
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |
- WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
+ WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
// fall through...
case STYLE_NO_FRAME:
case STYLE_NO_TITLE:
- mDialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
+ dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
}
- if (mDialog != null) {
- return (LayoutInflater) mDialog.getContext().getSystemService(
- Context.LAYOUT_INFLATER_SERVICE);
- }
- return (LayoutInflater) mActivity.getSystemService(
- Context.LAYOUT_INFLATER_SERVICE);
}
/**
diff -Nur support-v4-22.2.1/android/support/v4/app/Fragment.java support-v4-23.0.0/android/support/v4/app/Fragment.java
--- support-v4-22.2.1/android/support/v4/app/Fragment.java 2015-07-17 03:08:30.000000000 +0900
+++ support-v4-23.0.0/android/support/v4/app/Fragment.java 2015-07-22 08:36:20.000000000 +0900
@@ -22,11 +22,10 @@
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.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.StringRes;
import android.support.v4.util.SimpleArrayMap;
@@ -89,20 +88,21 @@
mArguments = in.readBundle();
mSavedFragmentState = in.readBundle();
}
-
- public Fragment instantiate(FragmentActivity activity, Fragment parent) {
+
+ public Fragment instantiate(FragmentHostCallback host, Fragment parent) {
if (mInstance != null) {
return mInstance;
}
-
+
+ final Context context = host.getContext();
if (mArguments != null) {
- mArguments.setClassLoader(activity.getClassLoader());
+ mArguments.setClassLoader(context.getClassLoader());
}
-
- mInstance = Fragment.instantiate(activity, mClassName, mArguments);
-
+
+ mInstance = Fragment.instantiate(context, mClassName, mArguments);
+
if (mSavedFragmentState != null) {
- mSavedFragmentState.setClassLoader(activity.getClassLoader());
+ mSavedFragmentState.setClassLoader(context.getClassLoader());
mInstance.mSavedFragmentState = mSavedFragmentState;
}
mInstance.setIndex(mIndex, parent);
@@ -113,14 +113,14 @@
mInstance.mTag = mTag;
mInstance.mRetainInstance = mRetainInstance;
mInstance.mDetached = mDetached;
- mInstance.mFragmentManager = activity.mFragments;
+ mInstance.mFragmentManager = host.mFragmentManager;
if (FragmentManagerImpl.DEBUG) Log.v(FragmentManagerImpl.TAG,
"Instantiated fragment " + mInstance);
return mInstance;
}
-
+
public int describeContents() {
return 0;
}
@@ -228,17 +228,17 @@
// 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.
FragmentManagerImpl mFragmentManager;
- // Activity this fragment is attached to.
- FragmentActivity mActivity;
+ // Host this fragment is attached to.
+ FragmentHostCallback mHost;
// Private fragment manager for child fragments inside of this one.
FragmentManagerImpl mChildFragmentManager;
@@ -348,10 +348,12 @@
public static final Parcelable.Creator<SavedState> CREATOR
= new Parcelable.Creator<SavedState>() {
+ @Override
public SavedState createFromParcel(Parcel in) {
return new SavedState(in, null);
}
+ @Override
public SavedState[] newArray(int size) {
return new SavedState[size];
}
@@ -606,22 +608,39 @@
}
/**
- * Return the Activity this fragment is currently associated with.
+ * Return the {@link Context} this fragment is currently associated with.
+ */
+ public Context getContext() {
+ return mHost == null ? null : mHost.getContext();
+ }
+
+ /**
+ * Return the {@link FragmentActivity} this fragment is currently associated with.
+ * May return {@code null} if the fragment is associated with a {@link Context}
+ * instead.
*/
final public FragmentActivity getActivity() {
- return mActivity;
+ return mHost == null ? null : (FragmentActivity) mHost.getActivity();
}
-
+
+ /**
+ * Return the host object of this fragment. May return {@code null} if the fragment
+ * isn't currently being hosted.
+ */
+ final public Object getHost() {
+ return mHost == null ? null : mHost.onGetHost();
+ }
+
/**
* Return <code>getActivity().getResources()</code>.
*/
final public Resources getResources() {
- if (mActivity == null) {
+ if (mHost == null) {
throw new IllegalStateException("Fragment " + this + " not attached to Activity");
}
- return mActivity.getResources();
+ return mHost.getContext().getResources();
}
-
+
/**
* Return a localized, styled CharSequence from the application's package's
* default string table.
@@ -701,7 +720,7 @@
* Return true if the fragment is currently added to its activity.
*/
final public boolean isAdded() {
- return mActivity != null && mAdded;
+ return mHost != null && mAdded;
}
/**
@@ -812,14 +831,14 @@
* 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) {
if (mHasMenu != hasMenu) {
mHasMenu = hasMenu;
if (isAdded() && !isHidden()) {
- mActivity.supportInvalidateOptionsMenu();
+ mHost.onSupportInvalidateOptionsMenu();
}
}
}
@@ -837,7 +856,7 @@
if (mMenuVisible != menuVisible) {
mMenuVisible = menuVisible;
if (mHasMenu && isAdded() && !isHidden()) {
- mActivity.supportInvalidateOptionsMenu();
+ mHost.onSupportInvalidateOptionsMenu();
}
}
}
@@ -878,42 +897,42 @@
if (mLoaderManager != null) {
return mLoaderManager;
}
- if (mActivity == null) {
+ if (mHost == null) {
throw new IllegalStateException("Fragment " + this + " not attached to Activity");
}
mCheckedForLoaderManager = true;
- mLoaderManager = mActivity.getLoaderManager(mWho, mLoadersStarted, true);
+ mLoaderManager = mHost.getLoaderManager(mWho, mLoadersStarted, true);
return mLoaderManager;
}
-
+
/**
- * Call {@link Activity#startActivity(Intent)} on the fragment's
+ * Call {@link Activity#startActivity(Intent)} from the fragment's
* containing Activity.
*/
public void startActivity(Intent intent) {
- if (mActivity == null) {
+ if (mHost == null) {
throw new IllegalStateException("Fragment " + this + " not attached to Activity");
}
- mActivity.startActivityFromFragment(this, intent, -1);
+ mHost.onStartActivityFromFragment(this /*fragment*/, intent, -1);
}
-
+
/**
- * Call {@link Activity#startActivityForResult(Intent, int)} on the fragment's
+ * Call {@link Activity#startActivityForResult(Intent, int)} from the fragment's
* containing Activity.
*/
public void startActivityForResult(Intent intent, int requestCode) {
- if (mActivity == null) {
+ if (mHost == null) {
throw new IllegalStateException("Fragment " + this + " not attached to Activity");
}
- mActivity.startActivityFromFragment(this, intent, requestCode);
+ mHost.onStartActivityFromFragment(this /*fragment*/, intent, requestCode);
}
-
+
/**
* 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.
@@ -924,19 +943,142 @@
*/
public void onActivityResult(int requestCode, int resultCode, Intent data) {
}
-
+
+ /**
+ * Requests permissions to be granted to this application. These permissions
+ * must be requested in your manifest, they should not be granted to your app,
+ * and they should have protection level {@link android.content.pm.PermissionInfo
+ * #PROTECTION_DANGEROUS dangerous}, regardless whether they are declared by
+ * the platform or a third-party app.
+ * <p>
+ * Normal permissions {@link android.content.pm.PermissionInfo#PROTECTION_NORMAL}
+ * are granted at install time if requested in the manifest. Signature permissions
+ * {@link android.content.pm.PermissionInfo#PROTECTION_SIGNATURE} are granted at
+ * install time if requested in the manifest and the signature of your app matches
+ * the signature of the app declaring the permissions.
+ * </p>
+ * <p>
+ * If your app does not have the requested permissions the user will be presented
+ * with UI for accepting them. After the user has accepted or rejected the
+ * requested permissions you will receive a callback on {@link
+ * #onRequestPermissionsResult(int, String[], int[])} reporting whether the
+ * permissions were granted or not.
+ * </p>
+ * <p>
+ * Note that requesting a permission does not guarantee it will be granted and
+ * your app should be able to run without having this permission.
+ * </p>
+ * <p>
+ * This method may start an activity allowing the user to choose which permissions
+ * to grant and which to reject. Hence, you should be prepared that your activity
+ * may be paused and resumed. Further, granting some permissions may require
+ * a restart of you application. In such a case, the system will recreate the
+ * activity stack before delivering the result to {@link
+ * #onRequestPermissionsResult(int, String[], int[])}.
+ * </p>
+ * <p>
+ * When checking whether you have a permission you should use {@link
+ * android.content.Context#checkSelfPermission(String)}.
+ * </p>
+ * <p>
+ * A sample permissions request looks like this:
+ * </p>
+ * <code><pre><p>
+ * private void showContacts() {
+ * if (getActivity().checkSelfPermission(Manifest.permission.READ_CONTACTS)
+ * != PackageManager.PERMISSION_GRANTED) {
+ * requestPermissions(new String[]{Manifest.permission.READ_CONTACTS},
+ * PERMISSIONS_REQUEST_READ_CONTACTS);
+ * } else {
+ * doShowContacts();
+ * }
+ * }
+ *
+ * {@literal @}Override
+ * public void onRequestPermissionsResult(int requestCode, String[] permissions,
+ * int[] grantResults) {
+ * if (requestCode == PERMISSIONS_REQUEST_READ_CONTACTS
+ * && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
+ * doShowContacts();
+ * }
+ * }
+ * </code></pre></p>
+ *
+ * @param permissions The requested permissions.
+ * @param requestCode Application specific request code to match with a result
+ * reported to {@link #onRequestPermissionsResult(int, String[], int[])}.
+ *
+ * @see #onRequestPermissionsResult(int, String[], int[])
+ * @see android.content.Context#checkSelfPermission(String)
+ */
+ public final void requestPermissions(@NonNull String[] permissions, int requestCode) {
+ if (mHost == null) {
+ throw new IllegalStateException("Fragment " + this + " not attached to Activity");
+ }
+ mHost.onRequestPermissionsFromFragment(this, permissions,requestCode);
+ }
+
+ /**
+ * Callback for the result from requesting permissions. This method
+ * is invoked for every call on {@link #requestPermissions(String[], int)}.
+ * <p>
+ * <strong>Note:</strong> It is possible that the permissions request interaction
+ * with the user is interrupted. In this case you will receive empty permissions
+ * and results arrays which should be treated as a cancellation.
+ * </p>
+ *
+ * @param requestCode The request code passed in {@link #requestPermissions(String[], int)}.
+ * @param permissions The requested permissions. Never null.
+ * @param grantResults The grant results for the corresponding permissions
+ * which is either {@link android.content.pm.PackageManager#PERMISSION_GRANTED}
+ * or {@link android.content.pm.PackageManager#PERMISSION_DENIED}. Never null.
+ *
+ * @see #requestPermissions(String[], int)
+ */
+ public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
+ @NonNull int[] grantResults) {
+ /* callback - do nothing */
+ }
+
+ /**
+ * Gets whether you should show UI with rationale for requesting a permission.
+ * You should do this only if you do not have the permission and the context in
+ * which the permission is requested does not clearly communicate to the user
+ * what would be the benefit from granting this permission.
+ * <p>
+ * For example, if you write a camera app, requesting the camera permission
+ * would be expected by the user and no rationale for why it is requested is
+ * needed. If however, the app needs location for tagging photos then a non-tech
+ * savvy user may wonder how location is related to taking photos. In this case
+ * you may choose to show UI with rationale of requesting this permission.
+ * </p>
+ *
+ * @param permission A permission your app wants to request.
+ * @return Whether you can show permission rationale UI.
+ *
+ * @see Context#checkSelfPermission(String)
+ * @see #requestPermissions(String[], int)
+ * @see #onRequestPermissionsResult(int, String[], int[])
+ */
+ public boolean shouldShowRequestPermissionRationale(@NonNull String permission) {
+ if (mHost != null) {
+ return mHost.onShouldShowRequestPermissionRationale(permission);
+ }
+ return false;
+ }
+
/**
* @hide Hack so that DialogFragment can make its Dialog before creating
* its views, and the view construction can use the dialog's context for
* inflation. Maybe this should become a public API. Note sure.
*/
public LayoutInflater getLayoutInflater(Bundle savedInstanceState) {
- LayoutInflater result = mActivity.getLayoutInflater().cloneInContext(mActivity);
+ LayoutInflater result = mHost.onGetLayoutInflater();
getChildFragmentManager(); // Init if needed; use raw implementation below.
LayoutInflaterCompat.setFactory(result, mChildFragmentManager.getLayoutInflaterFactory());
return result;
}
-
+
/**
* Called when a fragment is being created as part of a view layout
* inflation, typically from setting the content view of an activity. This
@@ -973,31 +1115,61 @@
* {@sample development/samples/ApiDemos/src/com/example/android/apis/app/FragmentArguments.java
* create}
*
- * @param activity The Activity that is inflating this fragment.
+ * @param context The Activity that is inflating this fragment.
* @param attrs The attributes at the tag where the fragment is
* being created.
* @param savedInstanceState If the fragment is being re-created from
* a previous saved state, this is the state.
*/
+ public void onInflate(Context context, AttributeSet attrs, Bundle savedInstanceState) {
+ mCalled = true;
+ final Activity hostActivity = mHost == null ? null : mHost.getActivity();
+ if (hostActivity != null) {
+ mCalled = false;
+ onInflate(hostActivity, attrs, savedInstanceState);
+ }
+ }
+
+ /**
+ * Called when a fragment is being created as part of a view layout
+ * inflation, typically from setting the content view of an activity.
+ * <p>Deprecated. See {@link #onInflate(Context, AttributeSet, Bundle)}.
+ */
+ @Deprecated
public void onInflate(Activity activity, AttributeSet attrs, Bundle savedInstanceState) {
mCalled = true;
}
/**
+ * Called when a fragment is first attached to its context.
+ * {@link #onCreate(Bundle)} will be called after this.
+ */
+ public void onAttach(Context context) {
+ mCalled = true;
+ final Activity hostActivity = mHost == null ? null : mHost.getActivity();
+ if (hostActivity != null) {
+ mCalled = false;
+ onAttach(hostActivity);
+ }
+ }
+
+ /**
* Called when a fragment is first attached to its activity.
* {@link #onCreate(Bundle)} will be called after this.
+ * <p>Deprecated. See {@link #onAttach(Context)}.
*/
+ @Deprecated
public void onAttach(Activity activity) {
mCalled = true;
}
-
+
/**
* Called when a fragment loads an animation.
*/
public Animation onCreateAnimation(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
@@ -1104,19 +1276,19 @@
*/
public void onStart() {
mCalled = true;
-
+
if (!mLoadersStarted) {
mLoadersStarted = true;
if (!mCheckedForLoaderManager) {
mCheckedForLoaderManager = true;
- mLoaderManager = mActivity.getLoaderManager(mWho, mLoadersStarted, false);
+ mLoaderManager = mHost.getLoaderManager(mWho, mLoadersStarted, false);
}
if (mLoaderManager != null) {
mLoaderManager.doStart();
}
}
}
-
+
/**
* Called when the fragment is visible to the user and actively running.
* This is generally
@@ -1198,7 +1370,7 @@
// + " mLoaderManager=" + mLoaderManager);
if (!mCheckedForLoaderManager) {
mCheckedForLoaderManager = true;
- mLoaderManager = mActivity.getLoaderManager(mWho, mLoadersStarted, false);
+ mLoaderManager = mHost.getLoaderManager(mWho, mLoadersStarted, false);
}
if (mLoaderManager != null) {
mLoaderManager.doDestroy();
@@ -1223,7 +1395,7 @@
mBackStackNesting = 0;
mFragmentManager = null;
mChildFragmentManager = null;
- mActivity = null;
+ mHost = null;
mFragmentId = 0;
mContainerId = 0;
mTag = null;
@@ -1335,6 +1507,7 @@
* It is not safe to hold onto the context menu after this method returns.
* {@inheritDoc}
*/
+ @Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
getActivity().onCreateContextMenu(menu, v, menuInfo);
}
@@ -1678,9 +1851,9 @@
writer.print(prefix); writer.print("mFragmentManager=");
writer.println(mFragmentManager);
}
- if (mActivity != null) {
- writer.print(prefix); writer.print("mActivity=");
- writer.println(mActivity);
+ if (mHost != null) {
+ writer.print(prefix); writer.print("mHost=");
+ writer.println(mHost);
}
if (mParentFragment != null) {
writer.print(prefix); writer.print("mParentFragment=");
@@ -1741,10 +1914,10 @@
void instantiateChildFragmentManager() {
mChildFragmentManager = new FragmentManagerImpl();
- mChildFragmentManager.attachActivity(mActivity, new FragmentContainer() {
+ mChildFragmentManager.attachController(mHost, new FragmentContainer() {
@Override
@Nullable
- public View findViewById(int id) {
+ public View onFindViewById(int id) {
if (mView == null) {
throw new IllegalStateException("Fragment does not have a view");
}
@@ -1752,7 +1925,7 @@
}
@Override
- public boolean hasView() {
+ public boolean onHasView() {
return (mView != null);
}
}, this);
@@ -1974,10 +2147,10 @@
mLoadersStarted = false;
if (!mCheckedForLoaderManager) {
mCheckedForLoaderManager = true;
- mLoaderManager = mActivity.getLoaderManager(mWho, mLoadersStarted, false);
+ mLoaderManager = mHost.getLoaderManager(mWho, mLoadersStarted, false);
}
if (mLoaderManager != null) {
- if (!mActivity.mRetaining) {
+ if (!mRetaining) {
mLoaderManager.doStop();
} else {
mLoaderManager.doRetain();
diff -Nur support-v4-22.2.1/android/support/v4/app/FragmentActivity.java support-v4-23.0.0/android/support/v4/app/FragmentActivity.java
--- support-v4-22.2.1/android/support/v4/app/FragmentActivity.java 2015-07-17 03:08:30.000000000 +0900
+++ support-v4-23.0.0/android/support/v4/app/FragmentActivity.java 2015-08-10 21:01:18.000000000 +0900
@@ -31,6 +31,7 @@
import android.util.AttributeSet;
import android.util.Log;
import android.view.KeyEvent;
+import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
@@ -40,6 +41,7 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.List;
/**
* Base class for activities that want to use the support-based
@@ -73,11 +75,13 @@
* state, this may be a snapshot slightly before what the user last saw.</p>
* </ul>
*/
-public class FragmentActivity extends Activity {
+public class FragmentActivity extends BaseFragmentActivityHoneycomb implements
+ ActivityCompat.OnRequestPermissionsResultCallback,
+ ActivityCompatApi23.RequestPermissionsRequestCodeValidator {
private static final String TAG = "FragmentActivity";
-
+
static final String FRAGMENTS_TAG = "android:support:fragments";
-
+
// This is the SDK API version of Honeycomb (3.0).
private static final int HONEYCOMB = 11;
@@ -103,21 +107,8 @@
}
};
- final FragmentManagerImpl mFragments = new FragmentManagerImpl();
- final FragmentContainer mContainer = new FragmentContainer() {
- @Override
- @Nullable
- public View findViewById(int id) {
- return FragmentActivity.this.findViewById(id);
- }
+ final FragmentController mFragments = FragmentController.createController(new HostCallbacks());
- @Override
- public boolean hasView() {
- Window window = FragmentActivity.this.getWindow();
- return (window != null && window.peekDecorView() != null);
- }
- };
-
boolean mCreated;
boolean mResumed;
boolean mStopped;
@@ -125,24 +116,18 @@
boolean mRetaining;
boolean mOptionsMenuInvalidated;
-
- boolean mCheckedForLoaderManager;
- boolean mLoadersStarted;
- SimpleArrayMap<String, LoaderManagerImpl> mAllLoaderManagers;
- LoaderManagerImpl mLoaderManager;
+ boolean mRequestedPermissionsFromFragment;
static final class NonConfigurationInstances {
- Object activity;
Object custom;
- SimpleArrayMap<String, Object> children;
- ArrayList<Fragment> fragments;
- SimpleArrayMap<String, LoaderManagerImpl> loaders;
+ List<Fragment> fragments;
+ SimpleArrayMap<String, LoaderManager> loaders;
}
-
+
// ------------------------------------------------------------------------
// HOOKS INTO ACTIVITY
// ------------------------------------------------------------------------
-
+
/**
* Dispatch incoming result to the correct fragment.
*/
@@ -152,12 +137,15 @@
int index = requestCode>>16;
if (index != 0) {
index--;
- if (mFragments.mActive == null || index < 0 || index >= mFragments.mActive.size()) {
+ final int activeFragmentsCount = mFragments.getActiveFragmentsCount();
+ if (activeFragmentsCount == 0 || index < 0 || index >= activeFragmentsCount) {
Log.w(TAG, "Activity result fragment index out of range: 0x"
+ Integer.toHexString(requestCode));
return;
}
- Fragment frag = mFragments.mActive.get(index);
+ final List<Fragment> activeFragments =
+ mFragments.getActiveFragments(new ArrayList<Fragment>(activeFragmentsCount));
+ Fragment frag = activeFragments.get(index);
if (frag == null) {
Log.w(TAG, "Activity result no fragment exists for index: 0x"
+ Integer.toHexString(requestCode));
@@ -166,7 +154,7 @@
}
return;
}
-
+
super.onActivityResult(requestCode, resultCode, data);
}
@@ -175,7 +163,7 @@
* as appropriate.
*/
public void onBackPressed() {
- if (!mFragments.popBackStackImmediate()) {
+ if (!mFragments.getSupportFragmentManager().popBackStackImmediate()) {
supportFinishAfterTransition();
}
}
@@ -246,20 +234,17 @@
/**
* Perform initialization of all fragments and loaders.
*/
+ @SuppressWarnings("deprecation")
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
- mFragments.attachActivity(this, mContainer, null);
- // Old versions of the platform didn't do this!
- if (getLayoutInflater().getFactory() == null) {
- getLayoutInflater().setFactory(this);
- }
-
+ mFragments.attachHost(null /*parent*/);
+
super.onCreate(savedInstanceState);
-
- NonConfigurationInstances nc = (NonConfigurationInstances)
- getLastNonConfigurationInstance();
+
+ NonConfigurationInstances nc =
+ (NonConfigurationInstances) getLastNonConfigurationInstance();
if (nc != null) {
- mAllLoaderManagers = nc.loaders;
+ mFragments.restoreLoaderNonConfig(nc.loaders);
}
if (savedInstanceState != null) {
Parcelable p = savedInstanceState.getParcelable(FRAGMENTS_TAG);
@@ -286,22 +271,11 @@
}
return super.onCreatePanelMenu(featureId, menu);
}
-
- /**
- * Add support for inflating the &lt;fragment> tag.
- */
- @Override
- @Nullable
- public View onCreateView(String name, @NonNull Context context, @NonNull AttributeSet attrs) {
- if (!"fragment".equals(name)) {
- return super.onCreateView(name, context, attrs);
- }
- final View v = mFragments.onCreateView(null, name, context, attrs);
- if (v == null) {
- return super.onCreateView(name, context, attrs);
- }
- return v;
+ @Override
+ final View dispatchFragmentsOnCreateView(View parent, String name, Context context,
+ AttributeSet attrs) {
+ return mFragments.onCreateView(parent, name, context, attrs);
}
/**
@@ -314,9 +288,7 @@
doReallyStop(false);
mFragments.dispatchDestroy();
- if (mLoaderManager != null) {
- mLoaderManager.doDestroy();
- }
+ mFragments.doLoaderDestroy();
}
/**
@@ -410,6 +382,13 @@
}
/**
+ * Hook in to note that fragment state is no longer saved.
+ */
+ public void onStateNotSaved() {
+ mFragments.noteStateNotSaved();
+ }
+
+ /**
* Dispatch onResume() to fragments. Note that for better inter-operation
* with older versions of the platform, at the point of this call the
* fragments attached to the activity are <em>not</em> resumed. This means
@@ -485,36 +464,17 @@
Object custom = onRetainCustomNonConfigurationInstance();
- ArrayList<Fragment> fragments = mFragments.retainNonConfig();
- boolean retainLoaders = false;
- if (mAllLoaderManagers != null) {
- // prune out any loader managers that were already stopped and so
- // have nothing useful to retain.
- final int N = mAllLoaderManagers.size();
- LoaderManagerImpl loaders[] = new LoaderManagerImpl[N];
- for (int i=N-1; i>=0; i--) {
- loaders[i] = mAllLoaderManagers.valueAt(i);
- }
- for (int i=0; i<N; i++) {
- LoaderManagerImpl lm = loaders[i];
- if (lm.mRetaining) {
- retainLoaders = true;
- } else {
- lm.doDestroy();
- mAllLoaderManagers.remove(lm.mWho);
- }
- }
- }
- if (fragments == null && !retainLoaders && custom == null) {
+ List<Fragment> fragments = mFragments.retainNonConfig();
+ SimpleArrayMap<String, LoaderManager> loaders = mFragments.retainLoaderNonConfig();
+
+ if (fragments == null && loaders == null && custom == null) {
return null;
}
-
+
NonConfigurationInstances nci = new NonConfigurationInstances();
- nci.activity = null;
nci.custom = custom;
- nci.children = null;
nci.fragments = fragments;
- nci.loaders = mAllLoaderManagers;
+ nci.loaders = loaders;
return nci;
}
@@ -549,35 +509,13 @@
mFragments.noteStateNotSaved();
mFragments.execPendingActions();
-
- if (!mLoadersStarted) {
- mLoadersStarted = true;
- if (mLoaderManager != null) {
- mLoaderManager.doStart();
- } else if (!mCheckedForLoaderManager) {
- mLoaderManager = getLoaderManager("(root)", mLoadersStarted, false);
- // the returned loader manager may be a new one, so we have to start it
- if ((mLoaderManager != null) && (!mLoaderManager.mStarted)) {
- mLoaderManager.doStart();
- }
- }
- mCheckedForLoaderManager = true;
- }
+
+ mFragments.doLoaderStart();
+
// NOTE: HC onStart goes here.
-
+
mFragments.dispatchStart();
- if (mAllLoaderManagers != null) {
- final int N = mAllLoaderManagers.size();
- LoaderManagerImpl loaders[] = new LoaderManagerImpl[N];
- for (int i=N-1; i>=0; i--) {
- loaders[i] = mAllLoaderManagers.valueAt(i);
- }
- for (int i=0; i<N; i++) {
- LoaderManagerImpl lm = loaders[i];
- lm.finishRetain();
- lm.doReportStart();
- }
- }
+ mFragments.reportLoaderStart();
}
/**
@@ -589,14 +527,14 @@
mStopped = true;
mHandler.sendEmptyMessage(MSG_REALLY_STOPPED);
-
+
mFragments.dispatchStop();
}
// ------------------------------------------------------------------------
// NEW METHODS
// ------------------------------------------------------------------------
-
+
/**
* Use this instead of {@link #onRetainNonConfigurationInstance()}.
* Retrieve later with {@link #getLastCustomNonConfigurationInstance()}.
@@ -609,6 +547,7 @@
* Return the value previously returned from
* {@link #onRetainCustomNonConfigurationInstance()}.
*/
+ @SuppressWarnings("deprecation")
public Object getLastCustomNonConfigurationInstance() {
NonConfigurationInstances nc = (NonConfigurationInstances)
getLastNonConfigurationInstance();
@@ -659,15 +598,8 @@
writer.print(mResumed); writer.print(" mStopped=");
writer.print(mStopped); writer.print(" mReallyStopped=");
writer.println(mReallyStopped);
- writer.print(innerPrefix); writer.print("mLoadersStarted=");
- writer.println(mLoadersStarted);
- if (mLoaderManager != null) {
- writer.print(prefix); writer.print("Loader Manager ");
- writer.print(Integer.toHexString(System.identityHashCode(mLoaderManager)));
- writer.println(":");
- mLoaderManager.dump(prefix + " ", fd, writer, args);
- }
- mFragments.dump(prefix, fd, writer, args);
+ mFragments.dumpLoaders(innerPrefix, fd, writer, args);
+ mFragments.getSupportFragmentManager().dump(prefix, fd, writer, args);
writer.print(prefix); writer.println("View Hierarchy:");
dumpViewHierarchy(prefix + " ", writer, getWindow().getDecorView());
}
@@ -776,16 +708,7 @@
* tell us what we need to know.
*/
void onReallyStop() {
- if (mLoadersStarted) {
- mLoadersStarted = false;
- if (mLoaderManager != null) {
- if (!mRetaining) {
- mLoaderManager.doStop();
- } else {
- mLoaderManager.doRetain();
- }
- }
- }
+ mFragments.doLoaderStop(mRetaining);
mFragments.dispatchReallyStop();
}
@@ -793,19 +716,24 @@
// ------------------------------------------------------------------------
// FRAGMENT SUPPORT
// ------------------------------------------------------------------------
-
+
/**
* Called when a fragment is attached to the activity.
*/
+ @SuppressWarnings("unused")
public void onAttachFragment(Fragment fragment) {
}
-
+
/**
* Return the FragmentManager for interacting with fragments associated
* with this activity.
*/
public FragmentManager getSupportFragmentManager() {
- return mFragments;
+ return mFragments.getSupportFragmentManager();
+ }
+
+ public LoaderManager getSupportLoaderManager() {
+ return mFragments.getSupportLoaderManager();
}
/**
@@ -820,10 +748,66 @@
super.startActivityForResult(intent, requestCode);
}
+ @Override
+ public final void validateRequestPermissionsRequestCode(int requestCode) {
+ // We use 8 bits of the request code to encode the fragment id when
+ // requesting permissions from a fragment. Hence, requestPermissions()
+ // should validate the code against that but we cannot override it as
+ // we can not then call super and also the ActivityCompat would call
+ // back to this override. To handle this we use dependency inversion
+ // where we are the validator of request codes when requesting
+ // permissions in ActivityCompat.
+ if (mRequestedPermissionsFromFragment) {
+ mRequestedPermissionsFromFragment = false;
+ } else if ((requestCode & 0xffffff00) != 0) {
+ throw new IllegalArgumentException("Can only use lower 8 bits for requestCode");
+ }
+ }
+
+ /**
+ * Callback for the result from requesting permissions. This method
+ * is invoked for every call on {@link #requestPermissions(String[], int)}.
+ * <p>
+ * <strong>Note:</strong> It is possible that the permissions request interaction
+ * with the user is interrupted. In this case you will receive empty permissions
+ * and results arrays which should be treated as a cancellation.
+ * </p>
+ *
+ * @param requestCode The request code passed in {@link #requestPermissions(String[], int)}.
+ * @param permissions The requested permissions. Never null.
+ * @param grantResults The grant results for the corresponding permissions
+ * which is either {@link android.content.pm.PackageManager#PERMISSION_GRANTED}
+ * or {@link android.content.pm.PackageManager#PERMISSION_DENIED}. Never null.
+ *
+ * @see #requestPermissions(String[], int)
+ */
+ public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
+ @NonNull int[] grantResults) {
+ int index = (requestCode>>8)&0xff;
+ if (index != 0) {
+ index--;
+ final int activeFragmentsCount = mFragments.getActiveFragmentsCount();
+ if (activeFragmentsCount == 0 || index < 0 || index >= activeFragmentsCount) {
+ Log.w(TAG, "Activity result fragment index out of range: 0x"
+ + Integer.toHexString(requestCode));
+ return;
+ }
+ final List<Fragment> activeFragments =
+ mFragments.getActiveFragments(new ArrayList<Fragment>(activeFragmentsCount));
+ Fragment frag = activeFragments.get(index);
+ if (frag == null) {
+ Log.w(TAG, "Activity result no fragment exists for index: 0x"
+ + Integer.toHexString(requestCode));
+ } else {
+ frag.onRequestPermissionsResult(requestCode&0xff, permissions, grantResults);
+ }
+ }
+ }
+
/**
* Called by Fragment.startActivityForResult() to implement its behavior.
*/
- public void startActivityFromFragment(Fragment fragment, Intent intent,
+ public void startActivityFromFragment(Fragment fragment, Intent intent,
int requestCode) {
if (requestCode == -1) {
super.startActivityForResult(intent, -1);
@@ -834,47 +818,98 @@
}
super.startActivityForResult(intent, ((fragment.mIndex+1)<<16) + (requestCode&0xffff));
}
-
- void invalidateSupportFragment(String who) {
- //Log.v(TAG, "invalidateSupportFragment: who=" + who);
- if (mAllLoaderManagers != null) {
- LoaderManagerImpl lm = mAllLoaderManagers.get(who);
- if (lm != null && !lm.mRetaining) {
- lm.doDestroy();
- mAllLoaderManagers.remove(who);
- }
- }
- }
-
- // ------------------------------------------------------------------------
- // LOADER SUPPORT
- // ------------------------------------------------------------------------
-
+
/**
- * Return the LoaderManager for this fragment, creating it if needed.
+ * Called by Fragment.requestPermissions() to implement its behavior.
*/
- public LoaderManager getSupportLoaderManager() {
- if (mLoaderManager != null) {
- return mLoaderManager;
+ private void requestPermissionsFromFragment(Fragment fragment, String[] permissions,
+ int requestCode) {
+ if (requestCode == -1) {
+ ActivityCompat.requestPermissions(this, permissions, requestCode);
+ return;
+ }
+ if ((requestCode&0xffffff00) != 0) {
+ throw new IllegalArgumentException("Can only use lower 8 bits for requestCode");
}
- mCheckedForLoaderManager = true;
- mLoaderManager = getLoaderManager("(root)", mLoadersStarted, true);
- return mLoaderManager;
+ mRequestedPermissionsFromFragment = true;
+ ActivityCompat.requestPermissions(this, permissions,
+ ((fragment.mIndex + 1) << 8) + (requestCode & 0xff));
}
-
- LoaderManagerImpl getLoaderManager(String who, boolean started, boolean create) {
- if (mAllLoaderManagers == null) {
- mAllLoaderManagers = new SimpleArrayMap<String, LoaderManagerImpl>();
- }
- LoaderManagerImpl lm = mAllLoaderManagers.get(who);
- if (lm == null) {
- if (create) {
- lm = new LoaderManagerImpl(who, this, started);
- mAllLoaderManagers.put(who, lm);
- }
- } else {
- lm.updateActivity(this);
+
+ class HostCallbacks extends FragmentHostCallback<FragmentActivity> {
+ public HostCallbacks() {
+ super(FragmentActivity.this /*fragmentActivity*/);
+ }
+
+ @Override
+ public void onDump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
+ FragmentActivity.this.dump(prefix, fd, writer, args);
+ }
+
+ @Override
+ public boolean onShouldSaveFragmentState(Fragment fragment) {
+ return !isFinishing();
+ }
+
+ @Override
+ public LayoutInflater onGetLayoutInflater() {
+ return FragmentActivity.this.getLayoutInflater().cloneInContext(FragmentActivity.this);
+ }
+
+ @Override
+ public FragmentActivity onGetHost() {
+ return FragmentActivity.this;
+ }
+
+ @Override
+ public void onSupportInvalidateOptionsMenu() {
+ FragmentActivity.this.supportInvalidateOptionsMenu();
+ }
+
+ @Override
+ public void onStartActivityFromFragment(Fragment fragment, Intent intent, int requestCode) {
+ FragmentActivity.this.startActivityFromFragment(fragment, intent, requestCode);
+ }
+
+ @Override
+ public void onRequestPermissionsFromFragment(@NonNull Fragment fragment,
+ @NonNull String[] permissions, int requestCode) {
+ FragmentActivity.this.requestPermissionsFromFragment(fragment, permissions,
+ requestCode);
+ }
+
+ @Override
+ public boolean onShouldShowRequestPermissionRationale(@NonNull String permission) {
+ return ActivityCompat.shouldShowRequestPermissionRationale(
+ FragmentActivity.this, permission);
+ }
+
+ @Override
+ public boolean onHasWindowAnimations() {
+ return getWindow() != null;
+ }
+
+ @Override
+ public int onGetWindowAnimations() {
+ final Window w = getWindow();
+ return (w == null) ? 0 : w.getAttributes().windowAnimations;
+ }
+
+ @Override
+ public void onAttachFragment(Fragment fragment) {
+ FragmentActivity.this.onAttachFragment(fragment);
+ }
+
+ @Nullable
+ @Override
+ public View onFindViewById(int id) {
+ return FragmentActivity.this.findViewById(id);
+ }
+
+ @Override
+ public boolean onHasView() {
+ final Window w = getWindow();
+ return (w != null && w.peekDecorView() != null);
}
- return lm;
}
}
diff -Nur support-v4-22.2.1/android/support/v4/app/FragmentContainer.java support-v4-23.0.0/android/support/v4/app/FragmentContainer.java
--- support-v4-22.2.1/android/support/v4/app/FragmentContainer.java 1970-01-01 09:00:00.000000000 +0900
+++ support-v4-23.0.0/android/support/v4/app/FragmentContainer.java 2015-06-23 08:43:44.000000000 +0900
@@ -0,0 +1,23 @@
+package android.support.v4.app;
+
+import android.support.annotation.IdRes;
+import android.support.annotation.Nullable;
+import android.view.View;
+
+
+/**
+ * Callbacks to a {@link Fragment}'s container.
+ */
+public abstract class FragmentContainer {
+ /**
+ * Return the view with the given resource ID. May return {@code null} if the
+ * view is not a child of this container.
+ */
+ @Nullable
+ public abstract View onFindViewById(@IdRes int id);
+
+ /**
+ * Return {@code true} if the container holds any view.
+ */
+ public abstract boolean onHasView();
+}
diff -Nur support-v4-22.2.1/android/support/v4/app/FragmentController.java support-v4-23.0.0/android/support/v4/app/FragmentController.java
--- support-v4-22.2.1/android/support/v4/app/FragmentController.java 1970-01-01 09:00:00.000000000 +0900
+++ support-v4-23.0.0/android/support/v4/app/FragmentController.java 2015-06-23 08:43:44.000000000 +0900
@@ -0,0 +1,396 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v4.app;
+
+import android.content.Context;
+import android.content.res.Configuration;
+import android.os.Parcelable;
+import android.support.v4.util.SimpleArrayMap;
+import android.util.AttributeSet;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Provides integration points with a {@link FragmentManager} for a fragment host.
+ * <p>
+ * It is the responsibility of the host to take care of the Fragment's lifecycle.
+ * The methods provided by {@link FragmentController} are for that purpose.
+ */
+public class FragmentController {
+ private final FragmentHostCallback<?> mHost;
+
+ /**
+ * Returns a {@link FragmentController}.
+ */
+ public static final FragmentController createController(FragmentHostCallback<?> callbacks) {
+ return new FragmentController(callbacks);
+ }
+
+ private FragmentController(FragmentHostCallback<?> callbacks) {
+ mHost = callbacks;
+ }
+
+ /**
+ * Returns a {@link FragmentManager} for this controller.
+ */
+ public FragmentManager getSupportFragmentManager() {
+ return mHost.getFragmentManagerImpl();
+ }
+
+ /**
+ * Returns a {@link LoaderManager}.
+ */
+ public LoaderManager getSupportLoaderManager() {
+ return mHost.getLoaderManagerImpl();
+ }
+
+ /**
+ * Returns the number of active fragments.
+ */
+ public int getActiveFragmentsCount() {
+ final List<Fragment> actives = mHost.mFragmentManager.mActive;
+ return actives == null ? 0 : actives.size();
+ }
+
+ /**
+ * Returns the list of active fragments.
+ */
+ public List<Fragment> getActiveFragments(List<Fragment> actives) {
+ if (mHost.mFragmentManager.mActive == null) {
+ return null;
+ }
+ if (actives == null) {
+ actives = new ArrayList<Fragment>(getActiveFragmentsCount());
+ }
+ actives.addAll(mHost.mFragmentManager.mActive);
+ return actives;
+ }
+
+ /**
+ * Attaches the host to the FragmentManager for this controller. The host must be
+ * attached before the FragmentManager can be used to manage Fragments.
+ */
+ public void attachHost(Fragment parent) {
+ mHost.mFragmentManager.attachController(
+ mHost, mHost /*container*/, parent);
+ }
+
+ /**
+ * Instantiates a Fragment's view.
+ *
+ * @param parent The parent that the created view will be placed
+ * in; <em>note that this may be null</em>.
+ * @param name Tag name to be inflated.
+ * @param context The context the view is being created in.
+ * @param attrs Inflation attributes as specified in XML file.
+ *
+ * @return view the newly created view
+ */
+ public View onCreateView(View parent, String name, Context context, AttributeSet attrs) {
+ return mHost.mFragmentManager.onCreateView(parent, name, context, attrs);
+ }
+
+ /**
+ * Marks the fragment state as unsaved. This allows for "state loss" detection.
+ */
+ public void noteStateNotSaved() {
+ mHost.mFragmentManager.noteStateNotSaved();
+ }
+
+ /**
+ * Saves the state for all Fragments.
+ */
+ public Parcelable saveAllState() {
+ return mHost.mFragmentManager.saveAllState();
+ }
+
+ /**
+ * Restores the saved state for all Fragments. The given Fragment list are Fragment
+ * instances retained across configuration changes.
+ *
+ * @see #retainNonConfig()
+ */
+ public void restoreAllState(Parcelable state, List<Fragment> nonConfigList) {
+ mHost.mFragmentManager.restoreAllState(state, nonConfigList);
+ }
+
+ /**
+ * Returns a list of Fragments that have opted to retain their instance across
+ * configuration changes.
+ */
+ public List<Fragment> retainNonConfig() {
+ return mHost.mFragmentManager.retainNonConfig();
+ }
+
+ /**
+ * Moves all Fragments managed by the controller's FragmentManager
+ * into the create state.
+ * <p>Call when Fragments should be created.
+ *
+ * @see Fragment#onCreate(Bundle)
+ */
+ public void dispatchCreate() {
+ mHost.mFragmentManager.dispatchCreate();
+ }
+
+ /**
+ * Moves all Fragments managed by the controller's FragmentManager
+ * into the activity created state.
+ * <p>Call when Fragments should be informed their host has been created.
+ *
+ * @see Fragment#onActivityCreated(Bundle)
+ */
+ public void dispatchActivityCreated() {
+ mHost.mFragmentManager.dispatchActivityCreated();
+ }
+
+ /**
+ * Moves all Fragments managed by the controller's FragmentManager
+ * into the start state.
+ * <p>Call when Fragments should be started.
+ *
+ * @see Fragment#onStart()
+ */
+ public void dispatchStart() {
+ mHost.mFragmentManager.dispatchStart();
+ }
+
+ /**
+ * Moves all Fragments managed by the controller's FragmentManager
+ * into the resume state.
+ * <p>Call when Fragments should be resumed.
+ *
+ * @see Fragment#onResume()
+ */
+ public void dispatchResume() {
+ mHost.mFragmentManager.dispatchResume();
+ }
+
+ /**
+ * Moves all Fragments managed by the controller's FragmentManager
+ * into the pause state.
+ * <p>Call when Fragments should be paused.
+ *
+ * @see Fragment#onPause()
+ */
+ public void dispatchPause() {
+ mHost.mFragmentManager.dispatchPause();
+ }
+
+ /**
+ * Moves all Fragments managed by the controller's FragmentManager
+ * into the stop state.
+ * <p>Call when Fragments should be stopped.
+ *
+ * @see Fragment#onStop()
+ */
+ public void dispatchStop() {
+ mHost.mFragmentManager.dispatchStop();
+ }
+
+ public void dispatchReallyStop() {
+ mHost.mFragmentManager.dispatchReallyStop();
+ }
+
+ /**
+ * Moves all Fragments managed by the controller's FragmentManager
+ * into the destroy view state.
+ * <p>Call when the Fragment's views should be destroyed.
+ *
+ * @see Fragment#onDestroyView()
+ */
+ public void dispatchDestroyView() {
+ mHost.mFragmentManager.dispatchDestroyView();
+ }
+
+ /**
+ * Moves all Fragments managed by the controller's FragmentManager
+ * into the destroy state.
+ * <p>Call when Fragments should be destroyed.
+ *
+ * @see Fragment#onDestroy()
+ */
+ public void dispatchDestroy() {
+ mHost.mFragmentManager.dispatchDestroy();
+ }
+
+ /**
+ * Lets all Fragments managed by the controller's FragmentManager
+ * know a configuration change occurred.
+ * <p>Call when there is a configuration change.
+ *
+ * @see Fragment#onConfigurationChanged(Configuration)
+ */
+ public void dispatchConfigurationChanged(Configuration newConfig) {
+ mHost.mFragmentManager.dispatchConfigurationChanged(newConfig);
+ }
+
+ /**
+ * Lets all Fragments managed by the controller's FragmentManager
+ * know the device is in a low memory condition.
+ * <p>Call when the device is low on memory and Fragment's should trim
+ * their memory usage.
+ *
+ * @see Fragment#onLowMemory()
+ */
+ public void dispatchLowMemory() {
+ mHost.mFragmentManager.dispatchLowMemory();
+ }
+
+ /**
+ * Lets all Fragments managed by the controller's FragmentManager
+ * know they should create an options menu.
+ * <p>Call when the Fragment should create an options menu.
+ *
+ * @return {@code true} if the options menu contains items to display
+ * @see Fragment#onCreateOptionsMenu(Menu, MenuInflater)
+ */
+ public boolean dispatchCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+ return mHost.mFragmentManager.dispatchCreateOptionsMenu(menu, inflater);
+ }
+
+ /**
+ * Lets all Fragments managed by the controller's FragmentManager
+ * know they should prepare their options menu for display.
+ * <p>Call immediately before displaying the Fragment's options menu.
+ *
+ * @return {@code true} if the options menu contains items to display
+ * @see Fragment#onPrepareOptionsMenu(Menu)
+ */
+ public boolean dispatchPrepareOptionsMenu(Menu menu) {
+ return mHost.mFragmentManager.dispatchPrepareOptionsMenu(menu);
+ }
+
+ /**
+ * Sends an option item selection event to the Fragments managed by the
+ * controller's FragmentManager. Once the event has been consumed,
+ * no additional handling will be performed.
+ * <p>Call immediately after an options menu item has been selected
+ *
+ * @return {@code true} if the options menu selection event was consumed
+ * @see Fragment#onOptionsItemSelected(MenuItem)
+ */
+ public boolean dispatchOptionsItemSelected(MenuItem item) {
+ return mHost.mFragmentManager.dispatchOptionsItemSelected(item);
+ }
+
+ /**
+ * Sends a context item selection event to the Fragments managed by the
+ * controller's FragmentManager. Once the event has been consumed,
+ * no additional handling will be performed.
+ * <p>Call immediately after an options menu item has been selected
+ *
+ * @return {@code true} if the context menu selection event was consumed
+ * @see Fragment#onContextItemSelected(MenuItem)
+ */
+ public boolean dispatchContextItemSelected(MenuItem item) {
+ return mHost.mFragmentManager.dispatchContextItemSelected(item);
+ }
+
+ /**
+ * Lets all Fragments managed by the controller's FragmentManager
+ * know their options menu has closed.
+ * <p>Call immediately after closing the Fragment's options menu.
+ *
+ * @see Fragment#onOptionsMenuClosed(Menu)
+ */
+ public void dispatchOptionsMenuClosed(Menu menu) {
+ mHost.mFragmentManager.dispatchOptionsMenuClosed(menu);
+ }
+
+ /**
+ * Execute any pending actions for the Fragments managed by the
+ * controller's FragmentManager.
+ * <p>Call when queued actions can be performed [eg when the
+ * Fragment moves into a start or resume state].
+ * @return {@code true} if queued actions were performed
+ */
+ public boolean execPendingActions() {
+ return mHost.mFragmentManager.execPendingActions();
+ }
+
+ /**
+ * Starts the loaders.
+ */
+ public void doLoaderStart() {
+ mHost.doLoaderStart();
+ }
+
+ /**
+ * Stops the loaders, optionally retaining their state. This is useful for keeping the
+ * loader state across configuration changes.
+ *
+ * @param retain When {@code true}, the loaders aren't stopped, but, their instances
+ * are retained in a started state
+ */
+ public void doLoaderStop(boolean retain) {
+ mHost.doLoaderStop(retain);
+ }
+
+ /**
+ * Retains the state of each of the loaders.
+ */
+ public void doLoaderRetain() {
+ mHost.doLoaderRetain();
+ }
+
+ /**
+ * Destroys the loaders and, if their state is not being retained, removes them.
+ */
+ public void doLoaderDestroy() {
+ mHost.doLoaderDestroy();
+ }
+
+ /**
+ * Lets the loaders know the host is ready to receive notifications.
+ */
+ public void reportLoaderStart() {
+ mHost.reportLoaderStart();
+ }
+
+ /**
+ * Returns a list of LoaderManagers that have opted to retain their instance across
+ * configuration changes.
+ */
+ public SimpleArrayMap<String, LoaderManager> retainLoaderNonConfig() {
+ return mHost.retainLoaderNonConfig();
+ }
+
+ /**
+ * Restores the saved state for all LoaderManagers. The given LoaderManager list are
+ * LoaderManager instances retained across configuration changes.
+ *
+ * @see #retainLoaderNonConfig()
+ */
+ public void restoreLoaderNonConfig(SimpleArrayMap<String, LoaderManager> loaderManagers) {
+ mHost.restoreLoaderNonConfig(loaderManagers);
+ }
+
+ /**
+ * Dumps the current state of the loaders.
+ */
+ public void dumpLoaders(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
+ mHost.dumpLoaders(prefix, fd, writer, args);
+ }
+}
diff -Nur support-v4-22.2.1/android/support/v4/app/FragmentHostCallback.java support-v4-23.0.0/android/support/v4/app/FragmentHostCallback.java
--- support-v4-22.2.1/android/support/v4/app/FragmentHostCallback.java 1970-01-01 09:00:00.000000000 +0900
+++ support-v4-23.0.0/android/support/v4/app/FragmentHostCallback.java 2015-06-23 08:43:44.000000000 +0900
@@ -0,0 +1,322 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v4.app;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Handler;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.v4.util.SimpleArrayMap;
+import android.view.LayoutInflater;
+import android.view.View;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
+/**
+ * Integration points with the Fragment host.
+ * <p>
+ * Fragments may be hosted by any object; such as an {@link Activity}. In order to
+ * host fragments, implement {@link FragmentHostCallback}, overriding the methods
+ * applicable to the host.
+ */
+public abstract class FragmentHostCallback<E> extends FragmentContainer {
+ private final Activity mActivity;
+ final Context mContext;
+ private final Handler mHandler;
+ final int mWindowAnimations;
+ final FragmentManagerImpl mFragmentManager = new FragmentManagerImpl();
+ private SimpleArrayMap<String, LoaderManager> mAllLoaderManagers;
+ private LoaderManagerImpl mLoaderManager;
+ private boolean mCheckedForLoaderManager;
+ private boolean mLoadersStarted;
+
+ public FragmentHostCallback(Context context, Handler handler, int windowAnimations) {
+ this(null /*activity*/, context, handler, windowAnimations);
+ }
+
+ FragmentHostCallback(FragmentActivity activity) {
+ this(activity, activity /*context*/, activity.mHandler, 0 /*windowAnimations*/);
+ }
+
+ FragmentHostCallback(Activity activity, Context context, Handler handler,
+ int windowAnimations) {
+ mActivity = activity;
+ mContext = context;
+ mHandler = handler;
+ mWindowAnimations = windowAnimations;
+ }
+
+ /**
+ * Print internal state into the given stream.
+ *
+ * @param prefix Desired prefix to prepend at each line of output.
+ * @param fd The raw file descriptor that the dump is being sent to.
+ * @param writer The PrintWriter to which you should dump your state. This will be closed
+ * for you after you return.
+ * @param args additional arguments to the dump request.
+ */
+ public void onDump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
+ }
+
+ /**
+ * Return {@code true} if the fragment's state needs to be saved.
+ */
+ public boolean onShouldSaveFragmentState(Fragment fragment) {
+ return true;
+ }
+
+ /**
+ * Return a {@link LayoutInflater}.
+ * See {@link Activity#getLayoutInflater()}.
+ */
+ public LayoutInflater onGetLayoutInflater() {
+ return (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ }
+
+ /**
+ * Return the object that's currently hosting the fragment. If a {@link Fragment}
+ * is hosted by a {@link FragmentActivity}, the object returned here should be
+ * the same object returned from {@link Fragment#getActivity()}.
+ */
+ @Nullable
+ public abstract E onGetHost();
+
+ /**
+ * Invalidates the activity's options menu.
+ * See {@link FragmentActivity#supportInvalidateOptionsMenu()}
+ */
+ public void onSupportInvalidateOptionsMenu() {
+ }
+
+ /**
+ * Starts a new {@link Activity} from the given fragment.
+ * See {@link FragmentActivity#startActivityForResult(Intent, int)}.
+ */
+ public void onStartActivityFromFragment(Fragment fragment, Intent intent, int requestCode) {
+ if (requestCode != -1) {
+ throw new IllegalStateException(
+ "Starting activity with a requestCode requires a FragmentActivity host");
+ }
+ mContext.startActivity(intent);
+ }
+
+ /**
+ * Requests permissions from the given fragment.
+ * See {@link FragmentActivity#requestPermissions(String[], int)}
+ */
+ public void onRequestPermissionsFromFragment(@NonNull Fragment fragment,
+ @NonNull String[] permissions, int requestCode) {
+ }
+
+ /**
+ * Checks wehter to show permission rationale UI from a fragment.
+ * See {@link FragmentActivity#shouldShowRequestPermissionRationale(String)}
+ */
+ public boolean onShouldShowRequestPermissionRationale(@NonNull String permission) {
+ return false;
+ }
+
+ /**
+ * Return {@code true} if there are window animations.
+ */
+ public boolean onHasWindowAnimations() {
+ return true;
+ }
+
+ /**
+ * Return the window animations.
+ */
+ public int onGetWindowAnimations() {
+ return mWindowAnimations;
+ }
+
+ @Nullable
+ @Override
+ public View onFindViewById(int id) {
+ return null;
+ }
+
+ @Override
+ public boolean onHasView() {
+ return true;
+ }
+
+ Activity getActivity() {
+ return mActivity;
+ }
+
+ Context getContext() {
+ return mContext;
+ }
+
+ Handler getHandler() {
+ return mHandler;
+ }
+
+ FragmentManagerImpl getFragmentManagerImpl() {
+ return mFragmentManager;
+ }
+
+ LoaderManagerImpl getLoaderManagerImpl() {
+ if (mLoaderManager != null) {
+ return mLoaderManager;
+ }
+ mCheckedForLoaderManager = true;
+ mLoaderManager = getLoaderManager("(root)", mLoadersStarted, true /*create*/);
+ return mLoaderManager;
+ }
+
+ void inactivateFragment(String who) {
+ //Log.v(TAG, "invalidateSupportFragment: who=" + who);
+ if (mAllLoaderManagers != null) {
+ LoaderManagerImpl lm = (LoaderManagerImpl) mAllLoaderManagers.get(who);
+ if (lm != null && !lm.mRetaining) {
+ lm.doDestroy();
+ mAllLoaderManagers.remove(who);
+ }
+ }
+ }
+
+ void onAttachFragment(Fragment fragment) {
+ }
+
+ void doLoaderStart() {
+ if (mLoadersStarted) {
+ return;
+ }
+ mLoadersStarted = true;
+
+ if (mLoaderManager != null) {
+ mLoaderManager.doStart();
+ } else if (!mCheckedForLoaderManager) {
+ mLoaderManager = getLoaderManager("(root)", mLoadersStarted, false);
+ // the returned loader manager may be a new one, so we have to start it
+ if ((mLoaderManager != null) && (!mLoaderManager.mStarted)) {
+ mLoaderManager.doStart();
+ }
+ }
+ mCheckedForLoaderManager = true;
+ }
+
+ // retain -- whether to stop the loader or retain it
+ void doLoaderStop(boolean retain) {
+ if (mLoaderManager == null) {
+ return;
+ }
+
+ if (!mLoadersStarted) {
+ return;
+ }
+ mLoadersStarted = false;
+
+ if (retain) {
+ mLoaderManager.doRetain();
+ } else {
+ mLoaderManager.doStop();
+ }
+ }
+
+ void doLoaderRetain() {
+ if (mLoaderManager == null) {
+ return;
+ }
+ mLoaderManager.doRetain();
+ }
+
+ void doLoaderDestroy() {
+ if (mLoaderManager == null) {
+ return;
+ }
+ mLoaderManager.doDestroy();
+ }
+
+ void reportLoaderStart() {
+ if (mAllLoaderManagers != null) {
+ final int N = mAllLoaderManagers.size();
+ LoaderManagerImpl loaders[] = new LoaderManagerImpl[N];
+ for (int i=N-1; i>=0; i--) {
+ loaders[i] = (LoaderManagerImpl) mAllLoaderManagers.valueAt(i);
+ }
+ for (int i=0; i<N; i++) {
+ LoaderManagerImpl lm = loaders[i];
+ lm.finishRetain();
+ lm.doReportStart();
+ }
+ }
+ }
+
+ LoaderManagerImpl getLoaderManager(String who, boolean started, boolean create) {
+ if (mAllLoaderManagers == null) {
+ mAllLoaderManagers = new SimpleArrayMap<String, LoaderManager>();
+ }
+ LoaderManagerImpl lm = (LoaderManagerImpl) mAllLoaderManagers.get(who);
+ if (lm == null) {
+ if (create) {
+ lm = new LoaderManagerImpl(who, this, started);
+ mAllLoaderManagers.put(who, lm);
+ }
+ } else {
+ lm.updateHostController(this);
+ }
+ return lm;
+ }
+
+ SimpleArrayMap<String, LoaderManager> retainLoaderNonConfig() {
+ boolean retainLoaders = false;
+ if (mAllLoaderManagers != null) {
+ // prune out any loader managers that were already stopped and so
+ // have nothing useful to retain.
+ final int N = mAllLoaderManagers.size();
+ LoaderManagerImpl loaders[] = new LoaderManagerImpl[N];
+ for (int i=N-1; i>=0; i--) {
+ loaders[i] = (LoaderManagerImpl) mAllLoaderManagers.valueAt(i);
+ }
+ for (int i=0; i<N; i++) {
+ LoaderManagerImpl lm = loaders[i];
+ if (lm.mRetaining) {
+ retainLoaders = true;
+ } else {
+ lm.doDestroy();
+ mAllLoaderManagers.remove(lm.mWho);
+ }
+ }
+ }
+
+ if (retainLoaders) {
+ return mAllLoaderManagers;
+ }
+ return null;
+ }
+
+ void restoreLoaderNonConfig(SimpleArrayMap<String, LoaderManager> loaderManagers) {
+ mAllLoaderManagers = loaderManagers;
+ }
+
+ void dumpLoaders(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
+ writer.print(prefix); writer.print("mLoadersStarted=");
+ writer.println(mLoadersStarted);
+ if (mLoaderManager != null) {
+ writer.print(prefix); writer.print("Loader Manager ");
+ writer.print(Integer.toHexString(System.identityHashCode(mLoaderManager)));
+ writer.println(":");
+ mLoaderManager.dump(prefix + " ", fd, writer, args);
+ }
+ }
+}
diff -Nur support-v4-22.2.1/android/support/v4/app/FragmentManager.java support-v4-23.0.0/android/support/v4/app/FragmentManager.java
--- support-v4-22.2.1/android/support/v4/app/FragmentManager.java 2015-07-17 03:08:30.000000000 +0900
+++ support-v4-23.0.0/android/support/v4/app/FragmentManager.java 2015-06-23 08:43:44.000000000 +0900
@@ -25,8 +25,8 @@
import android.os.Looper;
import android.os.Parcel;
import android.os.Parcelable;
+import android.support.annotation.CallSuper;
import android.support.annotation.IdRes;
-import android.support.annotation.Nullable;
import android.support.annotation.StringRes;
import android.support.v4.util.DebugUtils;
import android.support.v4.util.LogWriter;
@@ -399,15 +399,6 @@
}
/**
- * Callbacks from FragmentManagerImpl to its container.
- */
-interface FragmentContainer {
- @Nullable
- public View findViewById(@IdRes int id);
- public boolean hasView();
-}
-
-/**
* Container for fragments associated with an activity.
*/
final class FragmentManagerImpl extends FragmentManager implements LayoutInflaterFactory {
@@ -421,6 +412,39 @@
static final String VIEW_STATE_TAG = "android:view_state";
static final String USER_VISIBLE_HINT_TAG = "android:user_visible_hint";
+
+ static class AnimateOnHWLayerIfNeededListener implements AnimationListener {
+ private boolean mShouldRunOnHWLayer = false;
+ private View mView;
+ public AnimateOnHWLayerIfNeededListener(final View v, Animation anim) {
+ if (v == null || anim == null) {
+ return;
+ }
+ mView = v;
+ }
+
+ @Override
+ @CallSuper
+ public void onAnimationStart(Animation animation) {
+ mShouldRunOnHWLayer = shouldRunOnHWLayer(mView, animation);
+ if (mShouldRunOnHWLayer) {
+ ViewCompat.setLayerType(mView, ViewCompat.LAYER_TYPE_HARDWARE, null);
+ }
+ }
+
+ @Override
+ @CallSuper
+ public void onAnimationEnd(Animation animation) {
+ if (mShouldRunOnHWLayer) {
+ ViewCompat.setLayerType(mView, ViewCompat.LAYER_TYPE_NONE, null);
+ }
+ }
+
+ @Override
+ public void onAnimationRepeat(Animation animation) {
+ }
+ }
+
ArrayList<Runnable> mPendingActions;
Runnable[] mTmpActions;
boolean mExecutingActions;
@@ -438,7 +462,8 @@
ArrayList<OnBackStackChangedListener> mBackStackChangeListeners;
int mCurState = Fragment.INITIALIZING;
- FragmentActivity mActivity;
+ FragmentHostCallback mHost;
+ FragmentController mController;
FragmentContainer mContainer;
Fragment mParent;
@@ -459,14 +484,34 @@
}
};
+ static boolean modifiesAlpha(Animation anim) {
+ if (anim instanceof AlphaAnimation) {
+ return true;
+ } else if (anim instanceof AnimationSet) {
+ List<Animation> anims = ((AnimationSet) anim).getAnimations();
+ for (int i = 0; i < anims.size(); i++) {
+ if (anims.get(i) instanceof AlphaAnimation) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ static boolean shouldRunOnHWLayer(View v, Animation anim) {
+ return ViewCompat.getLayerType(v) == ViewCompat.LAYER_TYPE_NONE
+ && ViewCompat.hasOverlappingRendering(v)
+ && modifiesAlpha(anim);
+ }
+
private void throwException(RuntimeException ex) {
Log.e(TAG, ex.getMessage());
Log.e(TAG, "Activity state:");
LogWriter logw = new LogWriter(TAG);
PrintWriter pw = new PrintWriter(logw);
- if (mActivity != null) {
+ if (mHost != null) {
try {
- mActivity.dump(" ", null, pw, new String[] { });
+ mHost.onDump(" ", null, pw, new String[] { });
} catch (Exception e) {
Log.e(TAG, "Failed dumping state", e);
}
@@ -494,7 +539,7 @@
public void popBackStack() {
enqueueAction(new Runnable() {
@Override public void run() {
- popBackStackState(mActivity.mHandler, null, -1, 0);
+ popBackStackState(mHost.getHandler(), null, -1, 0);
}
}, false);
}
@@ -503,14 +548,14 @@
public boolean popBackStackImmediate() {
checkStateLoss();
executePendingTransactions();
- return popBackStackState(mActivity.mHandler, null, -1, 0);
+ return popBackStackState(mHost.getHandler(), null, -1, 0);
}
@Override
public void popBackStack(final String name, final int flags) {
enqueueAction(new Runnable() {
@Override public void run() {
- popBackStackState(mActivity.mHandler, name, -1, flags);
+ popBackStackState(mHost.getHandler(), name, -1, flags);
}
}, false);
}
@@ -519,7 +564,7 @@
public boolean popBackStackImmediate(String name, int flags) {
checkStateLoss();
executePendingTransactions();
- return popBackStackState(mActivity.mHandler, name, -1, flags);
+ return popBackStackState(mHost.getHandler(), name, -1, flags);
}
@Override
@@ -529,7 +574,7 @@
}
enqueueAction(new Runnable() {
@Override public void run() {
- popBackStackState(mActivity.mHandler, null, id, flags);
+ popBackStackState(mHost.getHandler(), null, id, flags);
}
}, false);
}
@@ -541,7 +586,7 @@
if (id < 0) {
throw new IllegalArgumentException("Bad id: " + id);
}
- return popBackStackState(mActivity.mHandler, null, id, flags);
+ return popBackStackState(mHost.getHandler(), null, id, flags);
}
@Override
@@ -628,7 +673,7 @@
if (mParent != null) {
DebugUtils.buildShortClassTag(mParent, sb);
} else {
- DebugUtils.buildShortClassTag(mActivity, sb);
+ DebugUtils.buildShortClassTag(mHost, sb);
}
sb.append("}}");
return sb.toString();
@@ -725,7 +770,7 @@
}
writer.print(prefix); writer.println("FragmentManager misc state:");
- writer.print(prefix); writer.print(" mActivity="); writer.println(mActivity);
+ writer.print(prefix); writer.print(" mHost="); writer.println(mHost);
writer.print(prefix); writer.print(" mContainer="); writer.println(mContainer);
if (mParent != null) {
writer.print(prefix); writer.print(" mParent="); writer.println(mParent);
@@ -775,7 +820,7 @@
anim.setDuration(ANIM_DUR);
return anim;
}
-
+
Animation loadAnimation(Fragment fragment, int transit, boolean enter,
int transitionStyle) {
Animation animObj = fragment.onCreateAnimation(transit, enter,
@@ -785,7 +830,7 @@
}
if (fragment.mNextAnim != 0) {
- Animation anim = AnimationUtils.loadAnimation(mActivity, fragment.mNextAnim);
+ Animation anim = AnimationUtils.loadAnimation(mHost.getContext(), fragment.mNextAnim);
if (anim != null) {
return anim;
}
@@ -799,24 +844,24 @@
if (styleIndex < 0) {
return null;
}
-
+
switch (styleIndex) {
case ANIM_STYLE_OPEN_ENTER:
- return makeOpenCloseAnimation(mActivity, 1.125f, 1.0f, 0, 1);
+ return makeOpenCloseAnimation(mHost.getContext(), 1.125f, 1.0f, 0, 1);
case ANIM_STYLE_OPEN_EXIT:
- return makeOpenCloseAnimation(mActivity, 1.0f, .975f, 1, 0);
+ return makeOpenCloseAnimation(mHost.getContext(), 1.0f, .975f, 1, 0);
case ANIM_STYLE_CLOSE_ENTER:
- return makeOpenCloseAnimation(mActivity, .975f, 1.0f, 0, 1);
+ return makeOpenCloseAnimation(mHost.getContext(), .975f, 1.0f, 0, 1);
case ANIM_STYLE_CLOSE_EXIT:
- return makeOpenCloseAnimation(mActivity, 1.0f, 1.075f, 1, 0);
+ return makeOpenCloseAnimation(mHost.getContext(), 1.0f, 1.075f, 1, 0);
case ANIM_STYLE_FADE_ENTER:
- return makeFadeAnimation(mActivity, 0, 1);
+ return makeFadeAnimation(mHost.getContext(), 0, 1);
case ANIM_STYLE_FADE_EXIT:
- return makeFadeAnimation(mActivity, 1, 0);
+ return makeFadeAnimation(mHost.getContext(), 1, 0);
}
- if (transitionStyle == 0 && mActivity.getWindow() != null) {
- transitionStyle = mActivity.getWindow().getAttributes().windowAnimations;
+ if (transitionStyle == 0 && mHost.onHasWindowAnimations()) {
+ transitionStyle = mHost.onGetWindowAnimations();
}
if (transitionStyle == 0) {
return null;
@@ -847,6 +892,22 @@
}
}