diff options
30 files changed, 1226 insertions, 352 deletions
diff --git a/api/current.txt b/api/current.txt index fc869ad..be01112 100644 --- a/api/current.txt +++ b/api/current.txt @@ -4328,9 +4328,11 @@ package android.app { method public boolean getAllowReturnTransitionOverlap(); method public final android.os.Bundle getArguments(); method public final android.app.FragmentManager getChildFragmentManager(); + method public android.content.Context getContext(); method public android.transition.Transition getEnterTransition(); method public android.transition.Transition getExitTransition(); method public final android.app.FragmentManager getFragmentManager(); + method public final java.lang.Object getHost(); method public final int getId(); method public android.app.LoaderManager getLoaderManager(); method public final android.app.Fragment getParentFragment(); @@ -4360,7 +4362,8 @@ package android.app { method public final boolean isVisible(); method public void onActivityCreated(android.os.Bundle); method public void onActivityResult(int, int, android.content.Intent); - method public void onAttach(android.app.Activity); + method public void onAttach(android.content.Context); + method public deprecated void onAttach(android.app.Activity); method public void onConfigurationChanged(android.content.res.Configuration); method public boolean onContextItemSelected(android.view.MenuItem); method public void onCreate(android.os.Bundle); @@ -4374,7 +4377,8 @@ package android.app { method public void onDetach(); method public void onHiddenChanged(boolean); method public deprecated void onInflate(android.util.AttributeSet, android.os.Bundle); - method public void onInflate(android.app.Activity, android.util.AttributeSet, android.os.Bundle); + method public void onInflate(android.content.Context, android.util.AttributeSet, android.os.Bundle); + method public deprecated void onInflate(android.app.Activity, android.util.AttributeSet, android.os.Bundle); method public void onLowMemory(); method public boolean onOptionsItemSelected(android.view.MenuItem); method public void onOptionsMenuClosed(android.view.Menu); @@ -4441,6 +4445,64 @@ package android.app { method public abstract boolean onBreadCrumbClick(android.app.FragmentManager.BackStackEntry, int); } + public abstract class FragmentContainer { + ctor public FragmentContainer(); + method public abstract android.view.View onFindViewById(int); + method public abstract boolean onHasView(); + } + + public class FragmentController { + method public void attachHost(android.app.Fragment); + method public static final android.app.FragmentController createController(android.app.FragmentHostCallback<?>); + method public void dispatchActivityCreated(); + method public void dispatchConfigurationChanged(android.content.res.Configuration); + method public boolean dispatchContextItemSelected(android.view.MenuItem); + method public void dispatchCreate(); + method public boolean dispatchCreateOptionsMenu(android.view.Menu, android.view.MenuInflater); + method public void dispatchDestroy(); + method public void dispatchDestroyView(); + method public void dispatchLowMemory(); + method public boolean dispatchOptionsItemSelected(android.view.MenuItem); + method public void dispatchOptionsMenuClosed(android.view.Menu); + method public void dispatchPause(); + method public boolean dispatchPrepareOptionsMenu(android.view.Menu); + method public void dispatchResume(); + method public void dispatchStart(); + method public void dispatchStop(); + method public void dispatchTrimMemory(int); + method public void doLoaderDestroy(); + method public void doLoaderStart(); + method public void doLoaderStop(boolean); + method public void dumpLoaders(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]); + method public boolean execPendingActions(); + method public android.app.Fragment findFragmentByWho(java.lang.String); + method public android.app.FragmentManager getFragmentManager(); + method public android.app.LoaderManager getLoaderManager(); + method public void noteStateNotSaved(); + method public android.view.View onCreateView(android.view.View, java.lang.String, android.content.Context, android.util.AttributeSet); + method public void reportLoaderStart(); + method public void restoreAllState(android.os.Parcelable, java.util.List<android.app.Fragment>); + method public void restoreLoaderNonConfig(android.util.ArrayMap<java.lang.String, android.app.LoaderManager>); + method public android.util.ArrayMap<java.lang.String, android.app.LoaderManager> retainLoaderNonConfig(); + method public java.util.List<android.app.Fragment> retainNonConfig(); + method public android.os.Parcelable saveAllState(); + } + + public abstract class FragmentHostCallback extends android.app.FragmentContainer { + ctor public FragmentHostCallback(android.content.Context, android.os.Handler, int); + method public void onDump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]); + method public android.view.View onFindViewById(int); + method public abstract E onGetHost(); + method public android.view.LayoutInflater onGetLayoutInflater(); + method public int onGetWindowAnimations(); + method public boolean onHasView(); + method public boolean onHasWindowAnimations(); + method public void onInvalidateOptionsMenu(); + method public boolean onShouldSaveFragmentState(android.app.Fragment); + method public void onStartActivityFromFragment(android.app.Fragment, android.content.Intent, int, android.os.Bundle); + method public boolean onUseFragmentManagerInflaterFactory(); + } + public abstract class FragmentManager { ctor public FragmentManager(); method public abstract void addOnBackStackChangedListener(android.app.FragmentManager.OnBackStackChangedListener); diff --git a/api/system-current.txt b/api/system-current.txt index 5416ef6..c4f96af 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -4418,9 +4418,11 @@ package android.app { method public boolean getAllowReturnTransitionOverlap(); method public final android.os.Bundle getArguments(); method public final android.app.FragmentManager getChildFragmentManager(); + method public android.content.Context getContext(); method public android.transition.Transition getEnterTransition(); method public android.transition.Transition getExitTransition(); method public final android.app.FragmentManager getFragmentManager(); + method public final java.lang.Object getHost(); method public final int getId(); method public android.app.LoaderManager getLoaderManager(); method public final android.app.Fragment getParentFragment(); @@ -4450,7 +4452,8 @@ package android.app { method public final boolean isVisible(); method public void onActivityCreated(android.os.Bundle); method public void onActivityResult(int, int, android.content.Intent); - method public void onAttach(android.app.Activity); + method public void onAttach(android.content.Context); + method public deprecated void onAttach(android.app.Activity); method public void onConfigurationChanged(android.content.res.Configuration); method public boolean onContextItemSelected(android.view.MenuItem); method public void onCreate(android.os.Bundle); @@ -4464,7 +4467,8 @@ package android.app { method public void onDetach(); method public void onHiddenChanged(boolean); method public deprecated void onInflate(android.util.AttributeSet, android.os.Bundle); - method public void onInflate(android.app.Activity, android.util.AttributeSet, android.os.Bundle); + method public void onInflate(android.content.Context, android.util.AttributeSet, android.os.Bundle); + method public deprecated void onInflate(android.app.Activity, android.util.AttributeSet, android.os.Bundle); method public void onLowMemory(); method public boolean onOptionsItemSelected(android.view.MenuItem); method public void onOptionsMenuClosed(android.view.Menu); @@ -4531,6 +4535,64 @@ package android.app { method public abstract boolean onBreadCrumbClick(android.app.FragmentManager.BackStackEntry, int); } + public abstract class FragmentContainer { + ctor public FragmentContainer(); + method public abstract android.view.View onFindViewById(int); + method public abstract boolean onHasView(); + } + + public class FragmentController { + method public void attachHost(android.app.Fragment); + method public static final android.app.FragmentController createController(android.app.FragmentHostCallback<?>); + method public void dispatchActivityCreated(); + method public void dispatchConfigurationChanged(android.content.res.Configuration); + method public boolean dispatchContextItemSelected(android.view.MenuItem); + method public void dispatchCreate(); + method public boolean dispatchCreateOptionsMenu(android.view.Menu, android.view.MenuInflater); + method public void dispatchDestroy(); + method public void dispatchDestroyView(); + method public void dispatchLowMemory(); + method public boolean dispatchOptionsItemSelected(android.view.MenuItem); + method public void dispatchOptionsMenuClosed(android.view.Menu); + method public void dispatchPause(); + method public boolean dispatchPrepareOptionsMenu(android.view.Menu); + method public void dispatchResume(); + method public void dispatchStart(); + method public void dispatchStop(); + method public void dispatchTrimMemory(int); + method public void doLoaderDestroy(); + method public void doLoaderStart(); + method public void doLoaderStop(boolean); + method public void dumpLoaders(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]); + method public boolean execPendingActions(); + method public android.app.Fragment findFragmentByWho(java.lang.String); + method public android.app.FragmentManager getFragmentManager(); + method public android.app.LoaderManager getLoaderManager(); + method public void noteStateNotSaved(); + method public android.view.View onCreateView(android.view.View, java.lang.String, android.content.Context, android.util.AttributeSet); + method public void reportLoaderStart(); + method public void restoreAllState(android.os.Parcelable, java.util.List<android.app.Fragment>); + method public void restoreLoaderNonConfig(android.util.ArrayMap<java.lang.String, android.app.LoaderManager>); + method public android.util.ArrayMap<java.lang.String, android.app.LoaderManager> retainLoaderNonConfig(); + method public java.util.List<android.app.Fragment> retainNonConfig(); + method public android.os.Parcelable saveAllState(); + } + + public abstract class FragmentHostCallback extends android.app.FragmentContainer { + ctor public FragmentHostCallback(android.content.Context, android.os.Handler, int); + method public void onDump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]); + method public android.view.View onFindViewById(int); + method public abstract E onGetHost(); + method public android.view.LayoutInflater onGetLayoutInflater(); + method public int onGetWindowAnimations(); + method public boolean onHasView(); + method public boolean onHasWindowAnimations(); + method public void onInvalidateOptionsMenu(); + method public boolean onShouldSaveFragmentState(android.app.Fragment); + method public void onStartActivityFromFragment(android.app.Fragment, android.content.Intent, int, android.os.Bundle); + method public boolean onUseFragmentManagerInflaterFactory(); + } + public abstract class FragmentManager { ctor public FragmentManager(); method public abstract void addOnBackStackChangedListener(android.app.FragmentManager.OnBackStackChangedListener); diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index 69cba78..e79e20c 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -108,6 +108,7 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.HashMap; +import java.util.List; /** * An activity is a single, focused thing that the user can do. Almost all @@ -706,8 +707,6 @@ public class Activity extends ContextThemeWrapper /*package*/ ActivityThread mMainThread; Activity mParent; boolean mCalled; - boolean mCheckedForLoaderManager; - boolean mLoadersStarted; /*package*/ boolean mResumed; private boolean mStopped; boolean mFinished; @@ -726,8 +725,8 @@ public class Activity extends ContextThemeWrapper static final class NonConfigurationInstances { Object activity; HashMap<String, Object> children; - ArrayList<Fragment> fragments; - ArrayMap<String, LoaderManagerImpl> loaders; + List<Fragment> fragments; + ArrayMap<String, LoaderManager> loaders; VoiceInteractor voiceInteractor; } /* package */ NonConfigurationInstances mLastNonConfigurationInstances; @@ -747,26 +746,13 @@ public class Activity extends ContextThemeWrapper private CharSequence mTitle; private int mTitleColor = 0; - final FragmentManagerImpl mFragments = new FragmentManagerImpl(); - final FragmentContainer mContainer = new FragmentContainer() { - @Override - @Nullable - public View findViewById(int id) { - return Activity.this.findViewById(id); - } - @Override - public boolean hasView() { - Window window = Activity.this.getWindow(); - return (window != null && window.peekDecorView() != null); - } - }; + // we must have a handler before the FragmentController is constructed + final Handler mHandler = new Handler(); + final FragmentController mFragments = FragmentController.createController(new HostCallbacks()); // Most recent call to requestVisibleBehind(). boolean mVisibleBehind; - ArrayMap<String, LoaderManagerImpl> mAllLoaderManagers; - LoaderManagerImpl mLoaderManager; - private static final class ManagedCursor { ManagedCursor(Cursor cursor) { mCursor = cursor; @@ -802,7 +788,6 @@ public class Activity extends ContextThemeWrapper private final Object mInstanceTracker = StrictMode.trackActivity(this); private Thread mUiThread; - final Handler mHandler = new Handler(); ActivityTransitionState mActivityTransitionState = new ActivityTransitionState(); SharedElementCallback mEnterTransitionListener = SharedElementCallback.NULL_CALLBACK; @@ -863,28 +848,7 @@ public class Activity extends ContextThemeWrapper * Return the LoaderManager for this activity, creating it if needed. */ public LoaderManager getLoaderManager() { - if (mLoaderManager != null) { - return mLoaderManager; - } - mCheckedForLoaderManager = true; - mLoaderManager = getLoaderManager("(root)", mLoadersStarted, true); - return mLoaderManager; - } - - LoaderManagerImpl getLoaderManager(String who, boolean started, boolean create) { - if (mAllLoaderManagers == null) { - mAllLoaderManagers = new ArrayMap<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); - } - return lm; + return mFragments.getLoaderManager(); } /** @@ -931,7 +895,7 @@ public class Activity extends ContextThemeWrapper protected void onCreate(@Nullable Bundle savedInstanceState) { if (DEBUG_LIFECYCLE) Slog.v(TAG, "onCreate " + this + ": " + savedInstanceState); if (mLastNonConfigurationInstances != null) { - mAllLoaderManagers = mLastNonConfigurationInstances.loaders; + mFragments.restoreLoaderNonConfig(mLastNonConfigurationInstances.loaders); } if (mActivityInfo.parentActivityName != null) { if (mActionBar == null) { @@ -1172,15 +1136,7 @@ public class Activity extends ContextThemeWrapper if (DEBUG_LIFECYCLE) Slog.v(TAG, "onStart " + this); mCalled = true; - if (!mLoadersStarted) { - mLoadersStarted = true; - if (mLoaderManager != null) { - mLoaderManager.doStart(); - } else if (!mCheckedForLoaderManager) { - mLoaderManager = getLoaderManager("(root)", mLoadersStarted, false); - } - mCheckedForLoaderManager = true; - } + mFragments.doLoaderStart(); getApplication().dispatchActivityStarted(this); } @@ -1873,27 +1829,9 @@ public class Activity extends ContextThemeWrapper NonConfigurationInstances retainNonConfigurationInstances() { Object activity = onRetainNonConfigurationInstance(); HashMap<String, Object> children = onRetainNonConfigurationChildInstances(); - 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 (activity == null && children == null && fragments == null && !retainLoaders + List<Fragment> fragments = mFragments.retainNonConfig(); + ArrayMap<String, LoaderManager> loaders = mFragments.retainLoaderNonConfig(); + if (activity == null && children == null && fragments == null && loaders == null && mVoiceInteractor == null) { return null; } @@ -1902,7 +1840,7 @@ public class Activity extends ContextThemeWrapper nci.activity = activity; nci.children = children; nci.fragments = fragments; - nci.loaders = mAllLoaderManagers; + nci.loaders = loaders; nci.voiceInteractor = mVoiceInteractor; return nci; } @@ -1924,18 +1862,7 @@ public class Activity extends ContextThemeWrapper * with this activity. */ public FragmentManager getFragmentManager() { - return mFragments; - } - - void invalidateFragment(String who) { - //Log.v(TAG, "invalidateFragmentIndex: index=" + index); - if (mAllLoaderManagers != null) { - LoaderManagerImpl lm = mAllLoaderManagers.get(who); - if (lm != null && !lm.mRetaining) { - lm.doDestroy(); - mAllLoaderManagers.remove(who); - } - } + return mFragments.getFragmentManager(); } /** @@ -2518,7 +2445,7 @@ public class Activity extends ContextThemeWrapper return; } - if (!mFragments.popBackStackImmediate()) { + if (!mFragments.getFragmentManager().popBackStackImmediate()) { finishAfterTransition(); } } @@ -5518,21 +5445,13 @@ public class Activity extends ContextThemeWrapper writer.print(mResumed); writer.print(" mStopped="); writer.print(mStopped); writer.print(" mFinished="); writer.println(mFinished); - writer.print(innerPrefix); writer.print("mLoadersStarted="); - writer.println(mLoadersStarted); writer.print(innerPrefix); writer.print("mChangingConfigurations="); writer.println(mChangingConfigurations); writer.print(innerPrefix); writer.print("mCurrentConfig="); writer.println(mCurrentConfig); - 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.getFragmentManager().dump(innerPrefix, fd, writer, args); if (getWindow() != null && getWindow().peekDecorView() != null && @@ -6128,7 +6047,7 @@ public class Activity extends ContextThemeWrapper Configuration config, String referrer, IVoiceInteractor voiceInteractor) { attachBaseContext(context); - mFragments.attachActivity(this, mContainer, null); + mFragments.attachHost(null /*parent*/); mWindow = new PhoneWindow(this); mWindow.setCallback(this); @@ -6211,18 +6130,7 @@ public class Activity extends ContextThemeWrapper " did not call through to super.onStart()"); } 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(); mActivityTransitionState.enterReady(this); } @@ -6328,16 +6236,7 @@ public class Activity extends ContextThemeWrapper final void performStop() { mDoReportFullyDrawn = false; - if (mLoadersStarted) { - mLoadersStarted = false; - if (mLoaderManager != null) { - if (!mChangingConfigurations) { - mLoaderManager.doStop(); - } else { - mLoaderManager.doRetain(); - } - } - } + mFragments.doLoaderStop(mChangingConfigurations /*retain*/); if (!mStopped) { if (mWindow != null) { @@ -6379,9 +6278,7 @@ public class Activity extends ContextThemeWrapper mWindow.destroy(); mFragments.dispatchDestroy(); onDestroy(); - if (mLoaderManager != null) { - mLoaderManager.doDestroy(); - } + mFragments.doLoaderDestroy(); if (mVoiceInteractor != null) { mVoiceInteractor.detachActivity(); } @@ -6541,4 +6438,74 @@ public class Activity extends ContextThemeWrapper return intent != null && PackageManager.ACTION_REQUEST_PERMISSIONS.equals(intent.getAction()); } + + class HostCallbacks extends FragmentHostCallback<Activity> { + public HostCallbacks() { + super(Activity.this /*activity*/); + } + + @Override + public void onDump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) { + Activity.this.dump(prefix, fd, writer, args); + } + + @Override + public boolean onShouldSaveFragmentState(Fragment fragment) { + return !isFinishing(); + } + + @Override + public LayoutInflater onGetLayoutInflater() { + final LayoutInflater result = Activity.this.getLayoutInflater(); + if (onUseFragmentManagerInflaterFactory()) { + return result.cloneInContext(Activity.this); + } + return result; + } + + @Override + public boolean onUseFragmentManagerInflaterFactory() { + // Newer platform versions use the child fragment manager's LayoutInflaterFactory. + return getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.LOLLIPOP; + } + + @Override + public Activity onGetHost() { + return Activity.this; + } + + @Override + public void onInvalidateOptionsMenu() { + Activity.this.invalidateOptionsMenu(); + } + + @Override + public void onStartActivityFromFragment(Fragment fragment, Intent intent, int requestCode, + Bundle options) { + Activity.this.startActivityFromFragment(fragment, intent, requestCode, options); + } + + @Override + public boolean onHasWindowAnimations() { + return getWindow() != null; + } + + @Override + public int onGetWindowAnimations() { + final Window w = getWindow(); + return (w == null) ? 0 : w.getAttributes().windowAnimations; + } + + @Nullable + @Override + public View onFindViewById(int id) { + return Activity.this.findViewById(id); + } + + @Override + public boolean onHasView() { + final Window w = getWindow(); + return (w != null && w.peekDecorView() != null); + } + } } diff --git a/core/java/android/app/BackStackRecord.java b/core/java/android/app/BackStackRecord.java index 8fb048b..49644a7 100644 --- a/core/java/android/app/BackStackRecord.java +++ b/core/java/android/app/BackStackRecord.java @@ -416,14 +416,14 @@ final class BackStackRecord extends FragmentTransaction implements 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; } @@ -868,7 +868,7 @@ final class BackStackRecord extends FragmentTransaction implements */ 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; @@ -926,7 +926,7 @@ final class BackStackRecord extends FragmentTransaction implements */ 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; @@ -1002,7 +1002,7 @@ final class BackStackRecord extends FragmentTransaction implements // 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()); // Go over all leaving fragments. for (int i = 0; i < firstOutFragments.size(); i++) { @@ -1275,7 +1275,7 @@ final class BackStackRecord extends FragmentTransaction implements */ private void 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) { Fragment inFragment = lastInFragments.get(containerId); Fragment outFragment = firstOutFragments.get(containerId); diff --git a/core/java/android/app/DialogFragment.java b/core/java/android/app/DialogFragment.java index bde5a61..2fb8cc2 100644 --- a/core/java/android/app/DialogFragment.java +++ b/core/java/android/app/DialogFragment.java @@ -410,7 +410,7 @@ public class DialogFragment extends Fragment return (LayoutInflater)mDialog.getContext().getSystemService( Context.LAYOUT_INFLATER_SERVICE); } - return (LayoutInflater)mActivity.getSystemService( + return (LayoutInflater) mHost.getContext().getSystemService( Context.LAYOUT_INFLATER_SERVICE); } diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java index 4fdae7f..91d810e 100644 --- a/core/java/android/app/Fragment.java +++ b/core/java/android/app/Fragment.java @@ -26,7 +26,6 @@ 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; @@ -94,19 +93,20 @@ final class FragmentState implements Parcelable { mSavedFragmentState = in.readBundle(); } - public Fragment instantiate(Activity 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); @@ -117,7 +117,7 @@ final class FragmentState implements Parcelable { 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); @@ -425,7 +425,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene FragmentManagerImpl mFragmentManager; // Activity this fragment is attached to. - Activity mActivity; + FragmentHostCallback mHost; // Private fragment manager for child fragments inside of this one. FragmentManagerImpl mChildFragmentManager; @@ -775,20 +775,36 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene } /** + * Return the {@link Context} this fragment is currently associated with. + */ + public Context getContext() { + return mHost == null ? null : mHost.getContext(); + } + + /** * Return the Activity this fragment is currently associated with. */ final public Activity getActivity() { - return mActivity; + return mHost == null ? null : mHost.getActivity(); + } + + /** + * Return the host object of this fragment. May return {@code null} if the fragment + * isn't currently being hosted. + */ + @Nullable + 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(); } /** @@ -870,7 +886,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene * Return true if the fragment is currently added to its activity. */ final public boolean isAdded() { - return mActivity != null && mAdded; + return mHost != null && mAdded; } /** @@ -1037,11 +1053,11 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene 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; } @@ -1065,15 +1081,15 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene * Context.startActivity(Intent, Bundle)} for more details. */ public void startActivity(Intent intent, Bundle options) { - if (mActivity == null) { + if (mHost == null) { throw new IllegalStateException("Fragment " + this + " not attached to Activity"); } if (options != null) { - mActivity.startActivityFromFragment(this, intent, -1, options); + mHost.onStartActivityFromFragment(this, intent, -1, options); } else { // Note we want to go through this call for compatibility with // applications that may have overridden the method. - mActivity.startActivityFromFragment(this, intent, -1); + mHost.onStartActivityFromFragment(this, intent, -1, null /*options*/); } } @@ -1090,10 +1106,10 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene * containing Activity. */ public void startActivityForResult(Intent intent, int requestCode, Bundle options) { - if (mActivity == null) { + if (mHost == null) { throw new IllegalStateException("Fragment " + this + " not attached to Activity"); } - mActivity.startActivityFromFragment(this, intent, requestCode, options); + mHost.onStartActivityFromFragment(this, intent, requestCode, options); } /** @@ -1181,11 +1197,12 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene * @see android.content.Context#checkSelfPermission(String) */ public final void requestPermissions(@NonNull String[] permissions, int requestCode) { - if (mActivity == null) { + if (mHost == null) { throw new IllegalStateException("Fragment " + this + " not attached to Activity"); } - Intent intent = mActivity.getPackageManager().buildRequestPermissionsIntent(permissions); - mActivity.startActivityFromFragment(this, intent, requestCode, null); + Intent intent = + mHost.getContext().getPackageManager().buildRequestPermissionsIntent(permissions); + mHost.onStartActivityFromFragment(this, intent, requestCode, null); } /** @@ -1211,19 +1228,16 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene * inflation. Maybe this should become a public API. Note sure. */ public LayoutInflater getLayoutInflater(Bundle savedInstanceState) { - // Newer platform versions use the child fragment manager's LayoutInflaterFactory. - if (mActivity.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.LOLLIPOP) { - LayoutInflater result = mActivity.getLayoutInflater().cloneInContext(mActivity); + final LayoutInflater result = mHost.onGetLayoutInflater(); + if (mHost.onUseFragmentManagerInflaterFactory()) { getChildFragmentManager(); // Init if needed; use raw implementation below. result.setPrivateFactory(mChildFragmentManager.getLayoutInflaterFactory()); - return result; - } else { - return mActivity.getLayoutInflater(); } + return result; } /** - * @deprecated Use {@link #onInflate(Activity, AttributeSet, Bundle)} instead. + * @deprecated Use {@link #onInflate(Context, AttributeSet, Bundle)} instead. */ @Deprecated public void onInflate(AttributeSet attrs, Bundle savedInstanceState) { @@ -1266,29 +1280,29 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene * {@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 Context 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(Activity activity, AttributeSet attrs, Bundle savedInstanceState) { + public void onInflate(Context context, AttributeSet attrs, Bundle savedInstanceState) { onInflate(attrs, savedInstanceState); mCalled = true; - TypedArray a = activity.obtainStyledAttributes(attrs, + TypedArray a = context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.Fragment); - mEnterTransition = loadTransition(activity, a, mEnterTransition, null, + mEnterTransition = loadTransition(context, a, mEnterTransition, null, com.android.internal.R.styleable.Fragment_fragmentEnterTransition); - mReturnTransition = loadTransition(activity, a, mReturnTransition, USE_DEFAULT_TRANSITION, + mReturnTransition = loadTransition(context, a, mReturnTransition, USE_DEFAULT_TRANSITION, com.android.internal.R.styleable.Fragment_fragmentReturnTransition); - mExitTransition = loadTransition(activity, a, mExitTransition, null, + mExitTransition = loadTransition(context, a, mExitTransition, null, com.android.internal.R.styleable.Fragment_fragmentExitTransition); - mReenterTransition = loadTransition(activity, a, mReenterTransition, USE_DEFAULT_TRANSITION, + mReenterTransition = loadTransition(context, a, mReenterTransition, USE_DEFAULT_TRANSITION, com.android.internal.R.styleable.Fragment_fragmentReenterTransition); - mSharedElementEnterTransition = loadTransition(activity, a, mSharedElementEnterTransition, + mSharedElementEnterTransition = loadTransition(context, a, mSharedElementEnterTransition, null, com.android.internal.R.styleable.Fragment_fragmentSharedElementEnterTransition); - mSharedElementReturnTransition = loadTransition(activity, a, mSharedElementReturnTransition, + mSharedElementReturnTransition = loadTransition(context, a, mSharedElementReturnTransition, USE_DEFAULT_TRANSITION, com.android.internal.R.styleable.Fragment_fragmentSharedElementReturnTransition); if (mAllowEnterTransitionOverlap == null) { @@ -1303,9 +1317,30 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene } /** - * Called when a fragment is first attached to its activity. + * @deprecated Use {@link #onInflate(Context, AttributeSet, Bundle)} instead. + */ + @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); + } + } + + /** + * @deprecated Use {@link #onAttach(Context)} instead. + */ + @Deprecated public void onAttach(Activity activity) { mCalled = true; } @@ -1428,7 +1463,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene mLoadersStarted = true; if (!mCheckedForLoaderManager) { mCheckedForLoaderManager = true; - mLoaderManager = mActivity.getLoaderManager(mWho, mLoadersStarted, false); + mLoaderManager = mHost.getLoaderManager(mWho, mLoadersStarted, false); } if (mLoaderManager != null) { mLoaderManager.doStart(); @@ -1521,7 +1556,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene // + " mLoaderManager=" + mLoaderManager); if (!mCheckedForLoaderManager) { mCheckedForLoaderManager = true; - mLoaderManager = mActivity.getLoaderManager(mWho, mLoadersStarted, false); + mLoaderManager = mHost.getLoaderManager(mWho, mLoadersStarted, false); } if (mLoaderManager != null) { mLoaderManager.doDestroy(); @@ -1546,7 +1581,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene mBackStackNesting = 0; mFragmentManager = null; mChildFragmentManager = null; - mActivity = null; + mHost = null; mFragmentId = 0; mContainerId = 0; mTag = null; @@ -2034,9 +2069,9 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene 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="); @@ -2094,10 +2129,10 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene 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"); } @@ -2105,7 +2140,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene } @Override - public boolean hasView() { + public boolean onHasView() { return (mView != null); } }, this); @@ -2319,13 +2354,13 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene mLoadersStarted = false; if (!mCheckedForLoaderManager) { mCheckedForLoaderManager = true; - mLoaderManager = mActivity.getLoaderManager(mWho, mLoadersStarted, false); + mLoaderManager = mHost.getLoaderManager(mWho, mLoadersStarted, false); } if (mLoaderManager != null) { - if (mActivity == null || !mActivity.mChangingConfigurations) { - mLoaderManager.doStop(); - } else { + if (mRetaining) { mLoaderManager.doRetain(); + } else { + mLoaderManager.doStop(); } } } diff --git a/core/java/android/app/FragmentContainer.java b/core/java/android/app/FragmentContainer.java new file mode 100644 index 0000000..b2e0300 --- /dev/null +++ b/core/java/android/app/FragmentContainer.java @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.app; + +import android.annotation.IdRes; +import android.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 --git a/core/java/android/app/FragmentController.java b/core/java/android/app/FragmentController.java new file mode 100644 index 0000000..28dadfa --- /dev/null +++ b/core/java/android/app/FragmentController.java @@ -0,0 +1,384 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.app; + +import android.annotation.Nullable; +import android.content.Context; +import android.content.res.Configuration; +import android.os.Bundle; +import android.os.Parcelable; +import android.util.ArrayMap; +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.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 getFragmentManager() { + return mHost.getFragmentManagerImpl(); + } + + /** + * Returns a {@link LoaderManager}. + */ + public LoaderManager getLoaderManager() { + return mHost.getLoaderManagerImpl(); + } + + /** + * Returns a fragment with the given identifier. + */ + @Nullable + public Fragment findFragmentByWho(String who) { + return mHost.mFragmentManager.findFragmentByWho(who); + } + + /** + * 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(); + } + + /** + * 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 trim their memory usage. + * <p>Call when the Fragment can release allocated memory [such as if + * the Fragment is in the background]. + * + * @see Fragment#onTrimMemory(int) + */ + public void dispatchTrimMemory(int level) { + mHost.mFragmentManager.dispatchTrimMemory(level); + } + + /** + * 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); + } + + /** + * 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 ArrayMap<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(ArrayMap<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 --git a/core/java/android/app/FragmentHostCallback.java b/core/java/android/app/FragmentHostCallback.java new file mode 100644 index 0000000..dad2c79 --- /dev/null +++ b/core/java/android/app/FragmentHostCallback.java @@ -0,0 +1,315 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.app; + +import android.annotation.Nullable; +import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.os.Handler; +import android.util.ArrayMap; +import android.util.AttributeSet; +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 ArrayMap<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(Activity 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 {@code true} if the FragmentManager's LayoutInflaterFactory should be used. + */ + public boolean onUseFragmentManagerInflaterFactory() { + return false; + } + + /** + * Return the object that's currently hosting the fragment. If a {@link Fragment} + * is hosted by a {@link Activity}, 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 Activity#invalidateOptionsMenu()} + */ + public void onInvalidateOptionsMenu() { + } + + /** + * Starts a new {@link Activity} from the given fragment. + * See {@link Activity#startActivityForResult(Intent, int)}. + */ + public void onStartActivityFromFragment(Fragment fragment, Intent intent, int requestCode, + Bundle options) { + if (requestCode != -1) { + throw new IllegalStateException( + "Starting activity with a requestCode requires a FragmentActivity host"); + } + mContext.startActivity(intent); + } + + /** + * 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 onFragmentInflate(Fragment fragment, AttributeSet attrs, Bundle savedInstanceState) { + fragment.onInflate(mContext, attrs, savedInstanceState); + } + + void onFragmentAttach(Fragment fragment) { + fragment.onAttach(mContext); + } + + void doLoaderStart() { + if (mLoadersStarted) { + return; + } + mLoadersStarted = true; + + if (mLoaderManager != null) { + mLoaderManager.doStart(); + } else if (!mCheckedForLoaderManager) { + mLoaderManager = getLoaderManager("(root)", mLoadersStarted, false); + } + mCheckedForLoaderManager = true; + } + + 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 ArrayMap<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; + } + + ArrayMap<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(ArrayMap<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 --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java index 975b20d..62436e9 100644 --- a/core/java/android/app/FragmentManager.java +++ b/core/java/android/app/FragmentManager.java @@ -19,9 +19,7 @@ package android.app; import android.animation.Animator; import android.animation.AnimatorInflater; import android.animation.AnimatorListenerAdapter; -import android.annotation.Nullable; import android.content.Context; -import android.annotation.IdRes; import android.content.res.Configuration; import android.content.res.TypedArray; import android.os.Bundle; @@ -48,6 +46,7 @@ import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; +import java.util.List; /** * Interface for interacting with {@link Fragment} objects inside of an @@ -393,15 +392,6 @@ final class FragmentManagerState implements Parcelable { } /** - * 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 LayoutInflater.Factory2 { @@ -430,7 +420,8 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate ArrayList<OnBackStackChangedListener> mBackStackChangeListeners; int mCurState = Fragment.INITIALIZING; - Activity mActivity; + FragmentHostCallback<?> mHost; + FragmentController mController; FragmentContainer mContainer; Fragment mParent; @@ -455,10 +446,10 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate Log.e(TAG, ex.getMessage()); LogWriter logw = new LogWriter(Log.ERROR, TAG); PrintWriter pw = new FastPrintWriter(logw, false, 1024); - if (mActivity != null) { + if (mHost != null) { Log.e(TAG, "Activity state:"); try { - mActivity.dump(" ", null, pw, new String[] { }); + mHost.onDump(" ", null, pw, new String[] { }); } catch (Exception e) { pw.flush(); Log.e(TAG, "Failed dumping state", e); @@ -490,7 +481,7 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate public void popBackStack() { enqueueAction(new Runnable() { @Override public void run() { - popBackStackState(mActivity.mHandler, null, -1, 0); + popBackStackState(mHost.getHandler(), null, -1, 0); } }, false); } @@ -499,14 +490,14 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate 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); } @@ -515,7 +506,7 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate public boolean popBackStackImmediate(String name, int flags) { checkStateLoss(); executePendingTransactions(); - return popBackStackState(mActivity.mHandler, name, -1, flags); + return popBackStackState(mHost.getHandler(), name, -1, flags); } @Override @@ -525,7 +516,7 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate } enqueueAction(new Runnable() { @Override public void run() { - popBackStackState(mActivity.mHandler, null, id, flags); + popBackStackState(mHost.getHandler(), null, id, flags); } }, false); } @@ -537,7 +528,7 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate if (id < 0) { throw new IllegalArgumentException("Bad id: " + id); } - return popBackStackState(mActivity.mHandler, null, id, flags); + return popBackStackState(mHost.getHandler(), null, id, flags); } @Override @@ -619,7 +610,7 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate if (mParent != null) { DebugUtils.buildShortClassTag(mParent, sb); } else { - DebugUtils.buildShortClassTag(mActivity, sb); + DebugUtils.buildShortClassTag(mHost, sb); } sb.append("}}"); return sb.toString(); @@ -716,7 +707,7 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate } 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); @@ -747,7 +738,7 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate } if (fragment.mNextAnim != 0) { - Animator anim = AnimatorInflater.loadAnimator(mActivity, fragment.mNextAnim); + Animator anim = AnimatorInflater.loadAnimator(mHost.getContext(), fragment.mNextAnim); if (anim != null) { return anim; } @@ -762,14 +753,14 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate return null; } - if (transitionStyle == 0 && mActivity.getWindow() != null) { - transitionStyle = mActivity.getWindow().getAttributes().windowAnimations; + if (transitionStyle == 0 && mHost.onHasWindowAnimations()) { + transitionStyle = mHost.onGetWindowAnimations(); } if (transitionStyle == 0) { return null; } - TypedArray attrs = mActivity.obtainStyledAttributes(transitionStyle, + TypedArray attrs = mHost.getContext().obtainStyledAttributes(transitionStyle, com.android.internal.R.styleable.FragmentAnimation); int anim = attrs.getResourceId(styleIndex, 0); attrs.recycle(); @@ -778,7 +769,7 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate return null; } - return AnimatorInflater.loadAnimator(mActivity, anim); + return AnimatorInflater.loadAnimator(mHost.getContext(), anim); } public void performPendingDeferredStart(Fragment f) { @@ -848,18 +839,18 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate } } } - f.mActivity = mActivity; + f.mHost = mHost; f.mParentFragment = mParent; f.mFragmentManager = mParent != null - ? mParent.mChildFragmentManager : mActivity.mFragments; + ? mParent.mChildFragmentManager : mHost.getFragmentManagerImpl(); f.mCalled = false; - f.onAttach(mActivity); + mHost.onFragmentAttach(f); if (!f.mCalled) { throw new SuperNotCalledException("Fragment " + f + " did not call through to super.onAttach()"); } if (f.mParentFragment == null) { - mActivity.onAttachFragment(f); + mHost.onFragmentAttach(f); } if (!f.mRetaining) { @@ -884,7 +875,7 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate if (!f.mFromLayout) { ViewGroup container = null; if (f.mContainerId != 0) { - container = (ViewGroup)mContainer.findViewById(f.mContainerId); + container = (ViewGroup)mContainer.onFindViewById(f.mContainerId); if (container == null && !f.mRestored) { throwException(new IllegalArgumentException( "No view found for id 0x" @@ -954,7 +945,7 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate if (f.mView != null) { // Need to save the current view state if not // done already. - if (!mActivity.isFinishing() && f.mSavedViewState == null) { + if (!mHost.onShouldSaveFragmentState(f) && f.mSavedViewState == null) { saveFragmentViewState(f); } } @@ -1030,7 +1021,7 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate if (!f.mRetaining) { makeInactive(f); } else { - f.mActivity = null; + f.mHost = null; f.mParentFragment = null; f.mFragmentManager = null; f.mChildFragmentManager = null; @@ -1053,7 +1044,7 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate } void moveToState(int newState, int transit, int transitStyle, boolean always) { - if (mActivity == null && newState != Fragment.INITIALIZING) { + if (mHost == null && newState != Fragment.INITIALIZING) { throw new IllegalStateException("No activity"); } @@ -1078,8 +1069,8 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate startPendingDeferredFragments(); } - if (mNeedMenuInvalidate && mActivity != null && mCurState == Fragment.RESUMED) { - mActivity.invalidateOptionsMenu(); + if (mNeedMenuInvalidate && mHost != null && mCurState == Fragment.RESUMED) { + mHost.onInvalidateOptionsMenu(); mNeedMenuInvalidate = false; } } @@ -1126,7 +1117,7 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate mAvailIndices = new ArrayList<Integer>(); } mAvailIndices.add(f.mIndex); - mActivity.invalidateFragment(f.mWho); + mHost.inactivateFragment(f.mWho); f.initState(); } @@ -1349,7 +1340,7 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate checkStateLoss(); } synchronized (this) { - if (mDestroyed || mActivity == null) { + if (mDestroyed || mHost == null) { throw new IllegalStateException("Activity has been destroyed"); } if (mPendingActions == null) { @@ -1357,8 +1348,8 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate } mPendingActions.add(action); if (mPendingActions.size() == 1) { - mActivity.mHandler.removeCallbacks(mExecCommit); - mActivity.mHandler.post(mExecCommit); + mHost.getHandler().removeCallbacks(mExecCommit); + mHost.getHandler().post(mExecCommit); } } } @@ -1427,7 +1418,7 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate throw new IllegalStateException("Recursive entry to executePendingTransactions"); } - if (Looper.myLooper() != mActivity.mHandler.getLooper()) { + if (Looper.myLooper() != mHost.getHandler().getLooper()) { throw new IllegalStateException("Must be called from main thread of process"); } @@ -1447,7 +1438,7 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate } mPendingActions.toArray(mTmpActions); mPendingActions.clear(); - mActivity.mHandler.removeCallbacks(mExecCommit); + mHost.getHandler().removeCallbacks(mExecCommit); } mExecutingActions = true; @@ -1737,7 +1728,7 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate return fms; } - void restoreAllState(Parcelable state, ArrayList<Fragment> nonConfig) { + void restoreAllState(Parcelable state, List<Fragment> nonConfig) { // If there is no saved state at all, then there can not be // any nonConfig fragments either, so that is that. if (state == null) return; @@ -1758,7 +1749,7 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate f.mAdded = false; f.mTarget = null; if (fs.mSavedFragmentState != null) { - fs.mSavedFragmentState.setClassLoader(mActivity.getClassLoader()); + fs.mSavedFragmentState.setClassLoader(mHost.getContext().getClassLoader()); f.mSavedViewState = fs.mSavedFragmentState.getSparseParcelableArray( FragmentManagerImpl.VIEW_STATE_TAG); f.mSavedFragmentState = fs.mSavedFragmentState; @@ -1775,7 +1766,7 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate for (int i=0; i<fms.mActive.length; i++) { FragmentState fs = fms.mActive[i]; if (fs != null) { - Fragment f = fs.instantiate(mActivity, mParent); + Fragment f = fs.instantiate(mHost, mParent); if (DEBUG) Log.v(TAG, "restoreAllState: active #" + i + ": " + f); mActive.add(f); // Now that the fragment is instantiated (or came from being @@ -1851,9 +1842,10 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate } } - public void attachActivity(Activity activity, FragmentContainer container, Fragment parent) { - if (mActivity != null) throw new IllegalStateException("Already attached"); - mActivity = activity; + public void attachController(FragmentHostCallback<?> host, FragmentContainer container, + Fragment parent) { + if (mHost != null) throw new IllegalStateException("Already attached"); + mHost = host; mContainer = container; mParent = parent; } @@ -1898,7 +1890,7 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate mDestroyed = true; execPendingActions(); moveToState(Fragment.INITIALIZING, false); - mActivity = null; + mHost = null; mContainer = null; mParent = null; } @@ -2024,8 +2016,8 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate @Override public void invalidateOptionsMenu() { - if (mActivity != null && mCurState == Fragment.RESUMED) { - mActivity.invalidateOptionsMenu(); + if (mHost != null && mCurState == Fragment.RESUMED) { + mHost.onInvalidateOptionsMenu(); } else { mNeedMenuInvalidate = true; } @@ -2115,7 +2107,7 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate fragment.mTag = tag; fragment.mInLayout = true; fragment.mFragmentManager = this; - fragment.onInflate(mActivity, attrs, fragment.mSavedFragmentState); + mHost.onFragmentInflate(fragment, attrs, fragment.mSavedFragmentState); addFragment(fragment, true); } else if (fragment.mInLayout) { // A fragment already exists and it is not one we restored from @@ -2132,7 +2124,7 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate // from last saved state), then give it the attributes to // initialize itself. if (!fragment.mRetaining) { - fragment.onInflate(mActivity, attrs, fragment.mSavedFragmentState); + mHost.onFragmentInflate(fragment, attrs, fragment.mSavedFragmentState); } } diff --git a/core/java/android/app/LoaderManager.java b/core/java/android/app/LoaderManager.java index b13b24a..f0e35c9 100644 --- a/core/java/android/app/LoaderManager.java +++ b/core/java/android/app/LoaderManager.java @@ -214,12 +214,12 @@ class LoaderManagerImpl extends LoaderManager { final String mWho; - Activity mActivity; boolean mStarted; boolean mRetaining; boolean mRetainingStarted; boolean mCreatingLoader; + private FragmentHostCallback mHost; final class LoaderInfo implements Loader.OnLoadCompleteListener<Object>, Loader.OnLoadCanceledListener<Object> { @@ -356,15 +356,15 @@ class LoaderManagerImpl extends LoaderManager { if (mCallbacks != null && mLoader != null && mHaveData && needReset) { if (DEBUG) Log.v(TAG, " Reseting: " + this); String lastBecause = null; - if (mActivity != null) { - lastBecause = mActivity.mFragments.mNoTransactionsBecause; - mActivity.mFragments.mNoTransactionsBecause = "onLoaderReset"; + if (mHost != null) { + lastBecause = mHost.mFragmentManager.mNoTransactionsBecause; + mHost.mFragmentManager.mNoTransactionsBecause = "onLoaderReset"; } try { mCallbacks.onLoaderReset(mLoader); } finally { - if (mActivity != null) { - mActivity.mFragments.mNoTransactionsBecause = lastBecause; + if (mHost != null) { + mHost.mFragmentManager.mNoTransactionsBecause = lastBecause; } } } @@ -465,25 +465,25 @@ class LoaderManagerImpl extends LoaderManager { mInactiveLoaders.remove(mId); } - if (mActivity != null && !hasRunningLoaders()) { - mActivity.mFragments.startPendingDeferredFragments(); + if (mHost != null && !hasRunningLoaders()) { + mHost.mFragmentManager.startPendingDeferredFragments(); } } void callOnLoadFinished(Loader<Object> loader, Object data) { if (mCallbacks != null) { String lastBecause = null; - if (mActivity != null) { - lastBecause = mActivity.mFragments.mNoTransactionsBecause; - mActivity.mFragments.mNoTransactionsBecause = "onLoadFinished"; + if (mHost != null) { + lastBecause = mHost.mFragmentManager.mNoTransactionsBecause; + mHost.mFragmentManager.mNoTransactionsBecause = "onLoadFinished"; } try { if (DEBUG) Log.v(TAG, " onLoadFinished in " + loader + ": " + loader.dataToString(data)); mCallbacks.onLoadFinished(loader, data); } finally { - if (mActivity != null) { - mActivity.mFragments.mNoTransactionsBecause = lastBecause; + if (mHost != null) { + mHost.mFragmentManager.mNoTransactionsBecause = lastBecause; } } mDeliveredData = true; @@ -530,14 +530,14 @@ class LoaderManagerImpl extends LoaderManager { } } - LoaderManagerImpl(String who, Activity activity, boolean started) { + LoaderManagerImpl(String who, FragmentHostCallback host, boolean started) { mWho = who; - mActivity = activity; + mHost = host; mStarted = started; } - void updateActivity(Activity activity) { - mActivity = activity; + void updateHostController(FragmentHostCallback host) { + mHost = host; } private LoaderInfo createLoader(int id, Bundle args, @@ -730,8 +730,8 @@ class LoaderManagerImpl extends LoaderManager { mInactiveLoaders.removeAt(idx); info.destroy(); } - if (mActivity != null && !hasRunningLoaders()) { - mActivity.mFragments.startPendingDeferredFragments(); + if (mHost != null && !hasRunningLoaders()) { + mHost.mFragmentManager.startPendingDeferredFragments(); } } @@ -849,7 +849,7 @@ class LoaderManagerImpl extends LoaderManager { sb.append("LoaderManager{"); sb.append(Integer.toHexString(System.identityHashCode(this))); sb.append(" in "); - DebugUtils.buildShortClassTag(mActivity, sb); + DebugUtils.buildShortClassTag(mHost, sb); sb.append("}}"); return sb.toString(); } diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java index 779448b..cf96145 100644 --- a/core/java/android/hardware/fingerprint/FingerprintManager.java +++ b/core/java/android/hardware/fingerprint/FingerprintManager.java @@ -626,7 +626,13 @@ public class FingerprintManager { return 0; } - private Handler mHandler = new Handler() { + private Handler mHandler; + + private class MyHandler extends Handler { + private MyHandler(Context context) { + super(context.getMainLooper()); + } + public void handleMessage(android.os.Message msg) { switch(msg.what) { case MSG_ENROLL_RESULT: @@ -711,6 +717,7 @@ public class FingerprintManager { if (mService == null) { Slog.v(TAG, "FingerprintManagerService was null"); } + mHandler = new MyHandler(context); } private int getCurrentUserId() { diff --git a/core/java/android/security/keymaster/KeymasterDefs.java b/core/java/android/security/keymaster/KeymasterDefs.java index d8834fe..0e2b8ba 100644 --- a/core/java/android/security/keymaster/KeymasterDefs.java +++ b/core/java/android/security/keymaster/KeymasterDefs.java @@ -238,6 +238,8 @@ public final class KeymasterDefs { sErrorCodeToString.put(KM_ERROR_UNSUPPORTED_EC_FIELD, "Unsupported EC field"); sErrorCodeToString.put(KM_ERROR_MISSING_NONCE, "Required IV missing"); sErrorCodeToString.put(KM_ERROR_INVALID_NONCE, "Invalid IV"); + sErrorCodeToString.put(KM_ERROR_CALLER_NONCE_PROHIBITED, + "Caller-provided IV not permitted"); sErrorCodeToString.put(KM_ERROR_UNIMPLEMENTED, "Not implemented"); sErrorCodeToString.put(KM_ERROR_UNKNOWN_ERROR, "Unknown error"); } diff --git a/core/java/android/view/LayoutInflater.java b/core/java/android/view/LayoutInflater.java index 457d6ad..1503728 100644 --- a/core/java/android/view/LayoutInflater.java +++ b/core/java/android/view/LayoutInflater.java @@ -946,25 +946,21 @@ public abstract class LayoutInflater { attrs, R.styleable.Include); final int id = a.getResourceId(R.styleable.Include_id, View.NO_ID); final int visibility = a.getInt(R.styleable.Include_visibility, -1); - final boolean hasWidth = a.hasValue(R.styleable.Include_layout_width); - final boolean hasHeight = a.hasValue(R.styleable.Include_layout_height); a.recycle(); - // We try to load the layout params set in the <include /> tag. If - // they don't exist, we will rely on the layout params set in the - // included XML file. - // During a layoutparams generation, a runtime exception is thrown - // if either layout_width or layout_height is missing. We catch - // this exception and set localParams accordingly: true means we - // successfully loaded layout params from the <include /> tag, - // false means we need to rely on the included layout params. + // We try to load the layout params set in the <include /> tag. + // If the parent can't generate layout params (ex. missing width + // or height for the framework ViewGroups, though this is not + // necessarily true of all ViewGroups) then we expect it to throw + // a runtime exception. + // We catch this exception and set localParams accordingly: true + // means we successfully loaded layout params from the <include> + // tag, false means we need to rely on the included layout params. ViewGroup.LayoutParams params = null; - if (hasWidth && hasHeight) { - try { - params = group.generateLayoutParams(attrs); - } catch (RuntimeException e) { - // Ignore, just fail over to child attrs. - } + try { + params = group.generateLayoutParams(attrs); + } catch (RuntimeException e) { + // Ignore, just fail over to child attrs. } if (params == null) { params = group.generateLayoutParams(childAttrs); diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp index 4c4a39d..d4069a1 100644 --- a/core/jni/android/graphics/BitmapFactory.cpp +++ b/core/jni/android/graphics/BitmapFactory.cpp @@ -261,7 +261,7 @@ static jobject doDecode(JNIEnv* env, SkStreamRewindable* stream, jobject padding SkBitmap* outputBitmap = NULL; unsigned int existingBufferSize = 0; if (javaBitmap != NULL) { - outputBitmap = GraphicsJNI::getSkBitmap(env, javaBitmap); + outputBitmap = GraphicsJNI::getSkBitmapDeprecated(env, javaBitmap); if (outputBitmap->isImmutable()) { ALOGW("Unable to reuse an immutable bitmap as an image decoder target."); javaBitmap = NULL; diff --git a/core/jni/android/graphics/BitmapRegionDecoder.cpp b/core/jni/android/graphics/BitmapRegionDecoder.cpp index 3525d07..aeea808 100644 --- a/core/jni/android/graphics/BitmapRegionDecoder.cpp +++ b/core/jni/android/graphics/BitmapRegionDecoder.cpp @@ -217,7 +217,7 @@ static jobject nativeDecodeRegion(JNIEnv* env, jobject, jlong brdHandle, if (tileBitmap != NULL) { // Re-use bitmap. - bitmap = GraphicsJNI::getSkBitmap(env, tileBitmap); + bitmap = GraphicsJNI::getSkBitmapDeprecated(env, tileBitmap); } if (bitmap == NULL) { bitmap = new SkBitmap; diff --git a/core/jni/android/graphics/Graphics.cpp b/core/jni/android/graphics/Graphics.cpp index 44037dd..f793df1 100644 --- a/core/jni/android/graphics/Graphics.cpp +++ b/core/jni/android/graphics/Graphics.cpp @@ -338,7 +338,7 @@ SkColorType GraphicsJNI::legacyBitmapConfigToColorType(jint legacyConfig) { return static_cast<SkColorType>(gConfig2ColorType[legacyConfig]); } -SkBitmap* GraphicsJNI::getSkBitmap(JNIEnv* env, jobject bitmap) { +SkBitmap* GraphicsJNI::getSkBitmapDeprecated(JNIEnv* env, jobject bitmap) { SkASSERT(env); SkASSERT(bitmap); SkASSERT(env->IsInstanceOf(bitmap, gBitmap_class)); @@ -348,6 +348,19 @@ SkBitmap* GraphicsJNI::getSkBitmap(JNIEnv* env, jobject bitmap) { return b; } +void GraphicsJNI::getSkBitmap(JNIEnv* env, jobject bitmap, SkBitmap* outBitmap) { + // TODO: We have to copy from the existing bitmap due to rowBytes not + // being updated on the SkPixelRef at reconfigure time. This is a short term + // problem that will be fixed with the specialized wrapper + *outBitmap = *getSkBitmapDeprecated(env, bitmap); +} + +SkPixelRef* GraphicsJNI::getSkPixelRef(JNIEnv* env, jobject bitmap) { + jlong bitmapHandle = env->GetLongField(bitmap, gBitmap_skBitmapPtr); + SkBitmap* b = reinterpret_cast<SkBitmap*>(bitmapHandle); + return b->pixelRef(); +} + SkColorType GraphicsJNI::getNativeBitmapColorType(JNIEnv* env, jobject jconfig) { SkASSERT(env); if (NULL == jconfig) { diff --git a/core/jni/android/graphics/GraphicsJNI.h b/core/jni/android/graphics/GraphicsJNI.h index d73507e..8eb43f8 100644 --- a/core/jni/android/graphics/GraphicsJNI.h +++ b/core/jni/android/graphics/GraphicsJNI.h @@ -49,7 +49,9 @@ public: static void point_to_jpointf(const SkPoint& point, JNIEnv*, jobject jpointf); static android::Canvas* getNativeCanvas(JNIEnv*, jobject canvas); - static SkBitmap* getSkBitmap(JNIEnv*, jobject bitmap); + static SkBitmap* getSkBitmapDeprecated(JNIEnv*, jobject bitmap); + static void getSkBitmap(JNIEnv*, jobject bitmap, SkBitmap* outBitmap); + static SkPixelRef* getSkPixelRef(JNIEnv*, jobject bitmap); static SkRegion* getNativeRegion(JNIEnv*, jobject region); // Given the 'native' long held by the Rasterizer.java object, return a diff --git a/core/jni/android/graphics/pdf/PdfRenderer.cpp b/core/jni/android/graphics/pdf/PdfRenderer.cpp index fc98cf9..876bea4 100644 --- a/core/jni/android/graphics/pdf/PdfRenderer.cpp +++ b/core/jni/android/graphics/pdf/PdfRenderer.cpp @@ -243,19 +243,21 @@ static void renderPageBitmap(FPDF_BITMAP bitmap, FPDF_PAGE page, int destLeft, i } static void nativeRenderPage(JNIEnv* env, jclass thiz, jlong documentPtr, jlong pagePtr, - jlong bitmapPtr, jint destLeft, jint destTop, jint destRight, jint destBottom, + jobject jbitmap, jint destLeft, jint destTop, jint destRight, jint destBottom, jlong matrixPtr, jint renderMode) { FPDF_PAGE page = reinterpret_cast<FPDF_PAGE>(pagePtr); - SkBitmap* skBitmap = reinterpret_cast<SkBitmap*>(bitmapPtr); SkMatrix* skMatrix = reinterpret_cast<SkMatrix*>(matrixPtr); - skBitmap->lockPixels(); + SkBitmap skBitmap; + GraphicsJNI::getSkBitmap(env, jbitmap, &skBitmap); - const int stride = skBitmap->width() * 4; + SkAutoLockPixels alp(skBitmap); - FPDF_BITMAP bitmap = FPDFBitmap_CreateEx(skBitmap->width(), skBitmap->height(), - FPDFBitmap_BGRA, skBitmap->getPixels(), stride); + const int stride = skBitmap.width() * 4; + + FPDF_BITMAP bitmap = FPDFBitmap_CreateEx(skBitmap.width(), skBitmap.height(), + FPDFBitmap_BGRA, skBitmap.getPixels(), stride); if (!bitmap) { ALOGE("Erorr creating bitmap"); @@ -278,8 +280,7 @@ static void nativeRenderPage(JNIEnv* env, jclass thiz, jlong documentPtr, jlong renderPageBitmap(bitmap, page, destLeft, destTop, destRight, destBottom, skMatrix, renderFlags); - skBitmap->notifyPixelsChanged(); - skBitmap->unlockPixels(); + skBitmap.notifyPixelsChanged(); } static JNINativeMethod gPdfRenderer_Methods[] = { @@ -287,7 +288,7 @@ static JNINativeMethod gPdfRenderer_Methods[] = { {"nativeClose", "(J)V", (void*) nativeClose}, {"nativeGetPageCount", "(J)I", (void*) nativeGetPageCount}, {"nativeScaleForPrinting", "(J)Z", (void*) nativeScaleForPrinting}, - {"nativeRenderPage", "(JJJIIIIJI)V", (void*) nativeRenderPage}, + {"nativeRenderPage", "(JJLandroid/graphics/Bitmap;IIIIJI)V", (void*) nativeRenderPage}, {"nativeOpenPageAndGetSize", "(JILandroid/graphics/Point;)J", (void*) nativeOpenPageAndGetSize}, {"nativeClosePage", "(J)V", (void*) nativeClosePage} }; diff --git a/core/jni/android/opengl/util.cpp b/core/jni/android/opengl/util.cpp index 5c2d0d0..bce2b33 100644 --- a/core/jni/android/opengl/util.cpp +++ b/core/jni/android/opengl/util.cpp @@ -618,23 +618,25 @@ static int getType(SkColorType colorType) static jint util_getInternalFormat(JNIEnv *env, jclass clazz, jobject jbitmap) { - SkBitmap const * nativeBitmap = GraphicsJNI::getSkBitmap(env, jbitmap); - return getInternalFormat(nativeBitmap->colorType()); + SkBitmap nativeBitmap; + GraphicsJNI::getSkBitmap(env, jbitmap, &nativeBitmap); + return getInternalFormat(nativeBitmap.colorType()); } static jint util_getType(JNIEnv *env, jclass clazz, jobject jbitmap) { - SkBitmap const * nativeBitmap = GraphicsJNI::getSkBitmap(env, jbitmap); - return getType(nativeBitmap->colorType()); + SkBitmap nativeBitmap; + GraphicsJNI::getSkBitmap(env, jbitmap, &nativeBitmap); + return getType(nativeBitmap.colorType()); } static jint util_texImage2D(JNIEnv *env, jclass clazz, jint target, jint level, jint internalformat, jobject jbitmap, jint type, jint border) { - SkBitmap const * nativeBitmap = GraphicsJNI::getSkBitmap(env, jbitmap); - const SkBitmap& bitmap(*nativeBitmap); + SkBitmap bitmap; + GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap); SkColorType colorType = bitmap.colorType(); if (internalformat < 0) { internalformat = getInternalFormat(colorType); @@ -680,8 +682,8 @@ static jint util_texSubImage2D(JNIEnv *env, jclass clazz, jint target, jint level, jint xoffset, jint yoffset, jobject jbitmap, jint format, jint type) { - SkBitmap const * nativeBitmap = GraphicsJNI::getSkBitmap(env, jbitmap); - const SkBitmap& bitmap(*nativeBitmap); + SkBitmap bitmap; + GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap); SkColorType colorType = bitmap.colorType(); if (format < 0) { format = getInternalFormat(colorType); diff --git a/core/jni/android_graphics_Canvas.cpp b/core/jni/android_graphics_Canvas.cpp index 3ae829b..5d08532 100644 --- a/core/jni/android_graphics_Canvas.cpp +++ b/core/jni/android_graphics_Canvas.cpp @@ -42,7 +42,7 @@ static void finalizer(JNIEnv* env, jobject clazz, jlong canvasHandle) { static jlong initRaster(JNIEnv* env, jobject, jobject jbitmap) { SkBitmap* bitmap = nullptr; if (jbitmap != NULL) { - bitmap = GraphicsJNI::getSkBitmap(env, jbitmap); + bitmap = GraphicsJNI::getSkBitmapDeprecated(env, jbitmap); } return reinterpret_cast<jlong>(Canvas::create_canvas( bitmap ? *bitmap : SkBitmap())); @@ -53,7 +53,7 @@ static jlong initRaster(JNIEnv* env, jobject, jobject jbitmap) { static void setBitmap(JNIEnv* env, jobject, jlong canvasHandle, jobject jbitmap) { SkBitmap* bitmap = nullptr; if (jbitmap != NULL) { - bitmap = GraphicsJNI::getSkBitmap(env, jbitmap); + bitmap = GraphicsJNI::getSkBitmapDeprecated(env, jbitmap); } get_canvas(canvasHandle)->setBitmap(bitmap ? *bitmap : SkBitmap()); } diff --git a/core/jni/android_view_PointerIcon.cpp b/core/jni/android_view_PointerIcon.cpp index f6d9a1a..d04adbf 100644 --- a/core/jni/android_view_PointerIcon.cpp +++ b/core/jni/android_view_PointerIcon.cpp @@ -80,10 +80,7 @@ status_t android_view_PointerIcon_load(JNIEnv* env, jobject pointerIconObj, jobj jobject bitmapObj = env->GetObjectField(loadedPointerIconObj, gPointerIconClassInfo.mBitmap); if (bitmapObj) { - SkBitmap* bitmap = GraphicsJNI::getSkBitmap(env, bitmapObj); - if (bitmap) { - outPointerIcon->bitmap = *bitmap; // use a shared pixel ref - } + GraphicsJNI::getSkBitmap(env, bitmapObj, &(outPointerIcon->bitmap)); env->DeleteLocalRef(bitmapObj); } diff --git a/core/jni/com_google_android_gles_jni_EGLImpl.cpp b/core/jni/com_google_android_gles_jni_EGLImpl.cpp index 7080e2a..baeb7dd 100644 --- a/core/jni/com_google_android_gles_jni_EGLImpl.cpp +++ b/core/jni/com_google_android_gles_jni_EGLImpl.cpp @@ -277,8 +277,9 @@ static void jni_eglCreatePixmapSurface(JNIEnv *_env, jobject _this, jobject out_ EGLConfig cnf = getConfig(_env, config); jint* base = 0; - SkBitmap const * nativeBitmap = GraphicsJNI::getSkBitmap(_env, native_pixmap); - SkPixelRef* ref = nativeBitmap ? nativeBitmap->pixelRef() : 0; + SkBitmap nativeBitmap; + GraphicsJNI::getSkBitmap(_env, native_pixmap, &nativeBitmap); + SkPixelRef* ref = nativeBitmap.pixelRef(); if (ref == NULL) { jniThrowException(_env, "java/lang/IllegalArgumentException", "Bitmap has no PixelRef"); return; @@ -289,10 +290,10 @@ static void jni_eglCreatePixmapSurface(JNIEnv *_env, jobject _this, jobject out_ egl_native_pixmap_t pixmap; pixmap.version = sizeof(pixmap); - pixmap.width = nativeBitmap->width(); - pixmap.height = nativeBitmap->height(); - pixmap.stride = nativeBitmap->rowBytes() / nativeBitmap->bytesPerPixel(); - pixmap.format = convertPixelFormat(nativeBitmap->colorType()); + pixmap.width = nativeBitmap.width(); + pixmap.height = nativeBitmap.height(); + pixmap.stride = nativeBitmap.rowBytes() / nativeBitmap.bytesPerPixel(); + pixmap.format = convertPixelFormat(nativeBitmap.colorType()); pixmap.data = (uint8_t*)ref->pixels(); base = beginNativeAttribList(_env, attrib_list); diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index 702f720..52b31b2 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -2725,12 +2725,11 @@ <attr name="value" /> </declare-styleable> - <!-- Attributes that can be assigned to an <include> tag. --> + <!-- Attributes that can be assigned to an <include> tag. + @hide --> <declare-styleable name="Include"> <attr name="id" /> <attr name="visibility" /> - <attr name="layout_width" /> - <attr name="layout_height" /> </declare-styleable> <!-- Attributes that can be used with a {@link android.view.ViewGroup} or any diff --git a/graphics/java/android/graphics/pdf/PdfRenderer.java b/graphics/java/android/graphics/pdf/PdfRenderer.java index b32dcc6..feb8052 100644 --- a/graphics/java/android/graphics/pdf/PdfRenderer.java +++ b/graphics/java/android/graphics/pdf/PdfRenderer.java @@ -380,7 +380,7 @@ public final class PdfRenderer implements AutoCloseable { final long transformPtr = (transform != null) ? transform.native_instance : 0; - nativeRenderPage(mNativeDocument, mNativePage, destination.getSkBitmap(), contentLeft, + nativeRenderPage(mNativeDocument, mNativePage, destination, contentLeft, contentTop, contentRight, contentBottom, transformPtr, renderMode); } @@ -425,7 +425,7 @@ public final class PdfRenderer implements AutoCloseable { private static native void nativeClose(long documentPtr); private static native int nativeGetPageCount(long documentPtr); private static native boolean nativeScaleForPrinting(long documentPtr); - private static native void nativeRenderPage(long documentPtr, long pagePtr, long destPtr, + private static native void nativeRenderPage(long documentPtr, long pagePtr, Bitmap dest, int destLeft, int destTop, int destRight, int destBottom, long matrixPtr, int renderMode); private static native long nativeOpenPageAndGetSize(long documentPtr, int pageIndex, Point outSize); diff --git a/keystore/java/android/security/KeyStoreCryptoOperationUtils.java b/keystore/java/android/security/KeyStoreCryptoOperationUtils.java index 313b527..e5933ad 100644 --- a/keystore/java/android/security/KeyStoreCryptoOperationUtils.java +++ b/keystore/java/android/security/KeyStoreCryptoOperationUtils.java @@ -74,6 +74,8 @@ abstract class KeyStoreCryptoOperationUtils { switch (beginOpResultCode) { case KeymasterDefs.KM_ERROR_INVALID_NONCE: return new InvalidAlgorithmParameterException("Invalid IV"); + case KeymasterDefs.KM_ERROR_CALLER_NONCE_PROHIBITED: + return new InvalidAlgorithmParameterException("Caller-provided IV not permitted"); } // General cases diff --git a/media/jni/android_media_MediaMetadataRetriever.cpp b/media/jni/android_media_MediaMetadataRetriever.cpp index 88a6771..59fb6d6 100644 --- a/media/jni/android_media_MediaMetadataRetriever.cpp +++ b/media/jni/android_media_MediaMetadataRetriever.cpp @@ -299,15 +299,16 @@ static jobject android_media_MediaMetadataRetriever_getFrameAtTime(JNIEnv *env, return NULL; } - SkBitmap *bitmap = GraphicsJNI::getSkBitmap(env, jBitmap); + SkBitmap bitmap; + GraphicsJNI::getSkBitmap(env, jBitmap, &bitmap); - bitmap->lockPixels(); - rotate((uint16_t*)bitmap->getPixels(), + bitmap.lockPixels(); + rotate((uint16_t*)bitmap.getPixels(), (uint16_t*)((char*)videoFrame + sizeof(VideoFrame)), videoFrame->mWidth, videoFrame->mHeight, videoFrame->mRotationAngle); - bitmap->unlockPixels(); + bitmap.unlockPixels(); if (videoFrame->mDisplayWidth != videoFrame->mWidth || videoFrame->mDisplayHeight != videoFrame->mHeight) { diff --git a/native/graphics/jni/bitmap.cpp b/native/graphics/jni/bitmap.cpp index ddb01a0..0521833 100644 --- a/native/graphics/jni/bitmap.cpp +++ b/native/graphics/jni/bitmap.cpp @@ -27,18 +27,16 @@ int AndroidBitmap_getInfo(JNIEnv* env, jobject jbitmap, return ANDROID_BITMAP_RESULT_BAD_PARAMETER; } - SkBitmap* bm = GraphicsJNI::getSkBitmap(env, jbitmap); - if (NULL == bm) { - return ANDROID_BITMAP_RESULT_JNI_EXCEPTION; - } + SkBitmap bm; + GraphicsJNI::getSkBitmap(env, jbitmap, &bm); if (info) { - info->width = bm->width(); - info->height = bm->height(); - info->stride = bm->rowBytes(); + info->width = bm.width(); + info->height = bm.height(); + info->stride = bm.rowBytes(); info->flags = 0; - switch (bm->colorType()) { + switch (bm.colorType()) { case kN32_SkColorType: info->format = ANDROID_BITMAP_FORMAT_RGBA_8888; break; @@ -64,17 +62,18 @@ int AndroidBitmap_lockPixels(JNIEnv* env, jobject jbitmap, void** addrPtr) { return ANDROID_BITMAP_RESULT_BAD_PARAMETER; } - SkBitmap* bm = GraphicsJNI::getSkBitmap(env, jbitmap); - if (NULL == bm) { + SkPixelRef* pixelRef = GraphicsJNI::getSkPixelRef(env, jbitmap); + if (!pixelRef) { return ANDROID_BITMAP_RESULT_JNI_EXCEPTION; } - bm->lockPixels(); - void* addr = bm->getPixels(); + pixelRef->lockPixels(); + void* addr = pixelRef->pixels(); if (NULL == addr) { - bm->unlockPixels(); + pixelRef->unlockPixels(); return ANDROID_BITMAP_RESULT_ALLOCATION_FAILED; } + pixelRef->ref(); if (addrPtr) { *addrPtr = addr; @@ -87,8 +86,8 @@ int AndroidBitmap_unlockPixels(JNIEnv* env, jobject jbitmap) { return ANDROID_BITMAP_RESULT_BAD_PARAMETER; } - SkBitmap* bm = GraphicsJNI::getSkBitmap(env, jbitmap); - if (NULL == bm) { + SkPixelRef* pixelRef = GraphicsJNI::getSkPixelRef(env, jbitmap); + if (!pixelRef) { return ANDROID_BITMAP_RESULT_JNI_EXCEPTION; } @@ -96,9 +95,11 @@ int AndroidBitmap_unlockPixels(JNIEnv* env, jobject jbitmap) { // bitmaps. Note that this will slow down read-only accesses to the // bitmaps, but the NDK methods are primarily intended to be used for // writes. - bm->notifyPixelsChanged(); + pixelRef->notifyPixelsChanged(); + + pixelRef->unlockPixels(); + pixelRef->unref(); - bm->unlockPixels(); return ANDROID_BITMAP_RESULT_SUCCESS; } diff --git a/rs/jni/android_renderscript_RenderScript.cpp b/rs/jni/android_renderscript_RenderScript.cpp index cbe87fc..ae48a5f 100644 --- a/rs/jni/android_renderscript_RenderScript.cpp +++ b/rs/jni/android_renderscript_RenderScript.cpp @@ -1102,9 +1102,8 @@ static jlong nAllocationCreateFromBitmap(JNIEnv *_env, jobject _this, jlong con, jlong type, jint mip, jobject jbitmap, jint usage) { - SkBitmap const * nativeBitmap = - GraphicsJNI::getSkBitmap(_env, jbitmap); - const SkBitmap& bitmap(*nativeBitmap); + SkBitmap bitmap; + GraphicsJNI::getSkBitmap(_env, jbitmap, &bitmap); bitmap.lockPixels(); const void* ptr = bitmap.getPixels(); @@ -1119,9 +1118,8 @@ static jlong nAllocationCreateBitmapBackedAllocation(JNIEnv *_env, jobject _this, jlong con, jlong type, jint mip, jobject jbitmap, jint usage) { - SkBitmap const * nativeBitmap = - GraphicsJNI::getSkBitmap(_env, jbitmap); - const SkBitmap& bitmap(*nativeBitmap); + SkBitmap bitmap; + GraphicsJNI::getSkBitmap(_env, jbitmap, &bitmap); bitmap.lockPixels(); const void* ptr = bitmap.getPixels(); @@ -1136,9 +1134,8 @@ static jlong nAllocationCubeCreateFromBitmap(JNIEnv *_env, jobject _this, jlong con, jlong type, jint mip, jobject jbitmap, jint usage) { - SkBitmap const * nativeBitmap = - GraphicsJNI::getSkBitmap(_env, jbitmap); - const SkBitmap& bitmap(*nativeBitmap); + SkBitmap bitmap; + GraphicsJNI::getSkBitmap(_env, jbitmap, &bitmap); bitmap.lockPixels(); const void* ptr = bitmap.getPixels(); @@ -1152,9 +1149,8 @@ nAllocationCubeCreateFromBitmap(JNIEnv *_env, jobject _this, jlong con, jlong ty static void nAllocationCopyFromBitmap(JNIEnv *_env, jobject _this, jlong con, jlong alloc, jobject jbitmap) { - SkBitmap const * nativeBitmap = - GraphicsJNI::getSkBitmap(_env, jbitmap); - const SkBitmap& bitmap(*nativeBitmap); + SkBitmap bitmap; + GraphicsJNI::getSkBitmap(_env, jbitmap, &bitmap); int w = bitmap.width(); int h = bitmap.height(); @@ -1169,9 +1165,8 @@ nAllocationCopyFromBitmap(JNIEnv *_env, jobject _this, jlong con, jlong alloc, j static void nAllocationCopyToBitmap(JNIEnv *_env, jobject _this, jlong con, jlong alloc, jobject jbitmap) { - SkBitmap const * nativeBitmap = - GraphicsJNI::getSkBitmap(_env, jbitmap); - const SkBitmap& bitmap(*nativeBitmap); + SkBitmap bitmap; + GraphicsJNI::getSkBitmap(_env, jbitmap, &bitmap); bitmap.lockPixels(); void* ptr = bitmap.getPixels(); diff --git a/services/core/jni/com_android_server_AssetAtlasService.cpp b/services/core/jni/com_android_server_AssetAtlasService.cpp index ad1d0f5..3d8905d 100644 --- a/services/core/jni/com_android_server_AssetAtlasService.cpp +++ b/services/core/jni/com_android_server_AssetAtlasService.cpp @@ -64,7 +64,7 @@ namespace android { static jboolean com_android_server_AssetAtlasService_upload(JNIEnv* env, jobject, jobject graphicBuffer, jobject bitmapHandle) { - SkBitmap& bitmap = *GraphicsJNI::getSkBitmap(env, bitmapHandle); + SkBitmap& bitmap = *GraphicsJNI::getSkBitmapDeprecated(env, bitmapHandle); SkAutoLockPixels alp(bitmap); // The goal of this method is to copy the bitmap into the GraphicBuffer |