/* * Copyright (C) 2006 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.content.Intent; import android.content.pm.ActivityInfo; import android.os.Binder; import android.os.Bundle; import android.util.Log; import android.view.Window; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; /** *
Helper class for managing multiple running embedded activities in the same
* process. This class is not normally used directly, but rather created for
* you as part of the {@link android.app.ActivityGroup} implementation.
*
* @see ActivityGroup
*
* @deprecated Use the new {@link Fragment} and {@link FragmentManager} APIs
* instead; these are also
* available on older platforms through the Android compatibility package.
*/
@Deprecated
public class LocalActivityManager {
private static final String TAG = "LocalActivityManager";
private static final boolean localLOGV = false;
// Internal token for an Activity being managed by LocalActivityManager.
private static class LocalActivityRecord extends Binder {
LocalActivityRecord(String _id, Intent _intent) {
id = _id;
intent = _intent;
}
final String id; // Unique name of this record.
Intent intent; // Which activity to run here.
ActivityInfo activityInfo; // Package manager info about activity.
Activity activity; // Currently instantiated activity.
Window window; // Activity's top-level window.
Bundle instanceState; // Last retrieved freeze state.
int curState = RESTORED; // Current state the activity is in.
}
static final int RESTORED = 0; // State restored, but no startActivity().
static final int INITIALIZING = 1; // Ready to launch (after startActivity()).
static final int CREATED = 2; // Created, not started or resumed.
static final int STARTED = 3; // Created and started, not resumed.
static final int RESUMED = 4; // Created started and resumed.
static final int DESTROYED = 5; // No longer with us.
/** Thread our activities are running in. */
private final ActivityThread mActivityThread;
/** The containing activity that owns the activities we create. */
private final Activity mParent;
/** The activity that is currently resumed. */
private LocalActivityRecord mResumed;
/** id -> record of all known activities. */
private final Map When there had previously been an activity started under this id,
* it may either be destroyed and a new one started, or the current
* one re-used, based on these conditions, in order: If the given Intent can not be resolved to an available Activity,
* this method throws {@link android.content.ActivityNotFoundException}.
*
* Warning: There is an issue where, if the Intent does not
* include an explicit component, we can restore the state for a different
* activity class than was previously running when the state was saved (if
* the set of available activities changes between those points).
*
* @param id Unique identifier of the activity to be started
* @param intent The Intent describing the activity to be started
*
* @return Returns the window of the activity. The caller needs to take
* care of adding this window to a view hierarchy, and likewise dealing
* with removing the old window if the activity has changed.
*
* @throws android.content.ActivityNotFoundException
*/
public Window startActivity(String id, Intent intent) {
if (mCurState == INITIALIZING) {
throw new IllegalStateException(
"Activities can't be added until the containing group has been created.");
}
boolean adding = false;
boolean sameIntent = false;
ActivityInfo aInfo = null;
// Already have information about the new activity id?
LocalActivityRecord r = mActivities.get(id);
if (r == null) {
// Need to create it...
r = new LocalActivityRecord(id, intent);
adding = true;
} else if (r.intent != null) {
sameIntent = r.intent.filterEquals(intent);
if (sameIntent) {
// We are starting the same activity.
aInfo = r.activityInfo;
}
}
if (aInfo == null) {
aInfo = mActivityThread.resolveActivityInfo(intent);
}
// Pause the currently running activity if there is one and only a single
// activity is allowed to be running at a time.
if (mSingleMode) {
LocalActivityRecord old = mResumed;
// If there was a previous activity, and it is not the current
// activity, we need to stop it.
if (old != null && old != r && mCurState == RESUMED) {
moveToState(old, STARTED);
}
}
if (adding) {
// It's a brand new world.
mActivities.put(id, r);
mActivityArray.add(r);
} else if (r.activityInfo != null) {
// If the new activity is the same as the current one, then
// we may be able to reuse it.
if (aInfo == r.activityInfo ||
(aInfo.name.equals(r.activityInfo.name) &&
aInfo.packageName.equals(r.activityInfo.packageName))) {
if (aInfo.launchMode != ActivityInfo.LAUNCH_MULTIPLE ||
(intent.getFlags()&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0) {
// The activity wants onNewIntent() called.
ArrayList Note: This does not change the current running activity, or
* start whatever activity was previously running when the state was saved.
* That is up to the client to do, in whatever way it thinks is best.
*
* @param state a previously saved state; does nothing if this is null
*
* @see #saveInstanceState
*/
public void dispatchCreate(Bundle state) {
if (state != null) {
for (String id : state.keySet()) {
try {
final Bundle astate = state.getBundle(id);
LocalActivityRecord r = mActivities.get(id);
if (r != null) {
r.instanceState = astate;
} else {
r = new LocalActivityRecord(id, null);
r.instanceState = astate;
mActivities.put(id, r);
mActivityArray.add(r);
}
} catch (Exception e) {
// Recover from -all- app errors.
Log.e(TAG, "Exception thrown when restoring LocalActivityManager state", e);
}
}
}
mCurState = CREATED;
}
/**
* Retrieve the state of all activities known by the group. For
* activities that have previously run and are now stopped or finished, the
* last saved state is used. For the current running activity, its
* {@link Activity#onSaveInstanceState} is called to retrieve its current state.
*
* @return a Bundle holding the newly created state of all known activities
*
* @see #dispatchCreate
*/
public Bundle saveInstanceState() {
Bundle state = null;
// FIXME: child activities will freeze as part of onPaused. Do we
// need to do this here?
final int N = mActivityArray.size();
for (int i=0; i
*
*
*