ActivityManager.java 8.38 KB
Newer Older
Alexander Ivanov's avatar
Alexander Ivanov committed
1 2
/**
 * Copyright (c) 2013, Redsolution LTD. All rights reserved.
3
 *
Alexander Ivanov's avatar
Alexander Ivanov committed
4 5
 * This file is part of Xabber project; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License, Version 3.
6
 *
Alexander Ivanov's avatar
Alexander Ivanov committed
7 8 9 10
 * Xabber is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
11
 *
Alexander Ivanov's avatar
Alexander Ivanov committed
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
 * You should have received a copy of the GNU General Public License,
 * along with this program. If not, see http://www.gnu.org/licenses/.
 */
package com.xabber.android.data;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.widget.Toast;

import com.xabber.android.ui.ContactList;
import com.xabber.android.ui.LoadActivity;
import com.xabber.androiddev.R;

27 28 29 30 31
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Map.Entry;
import java.util.WeakHashMap;

Alexander Ivanov's avatar
Alexander Ivanov committed
32 33
/**
 * Activity stack manager.
34
 *
Alexander Ivanov's avatar
Alexander Ivanov committed
35 36
 * @author alexander.ivanov
 */
37
public class ActivityManager implements OnUnloadListener {
Alexander Ivanov's avatar
Alexander Ivanov committed
38

39
    private static final String EXTRA_TASK_INDEX = "com.xabber.android.data.ActivityManager.EXTRA_TASK_INDEX";
Alexander Ivanov's avatar
Alexander Ivanov committed
40

41
    private static final boolean LOG = true;
Alexander Ivanov's avatar
Alexander Ivanov committed
42

43
    private final Application application;
Alexander Ivanov's avatar
Alexander Ivanov committed
44

45 46 47 48
    /**
     * List of launched activities.
     */
    private final ArrayList<Activity> activities;
Alexander Ivanov's avatar
Alexander Ivanov committed
49

50 51 52 53
    /**
     * Next index of task.
     */
    private int nextTaskIndex;
Alexander Ivanov's avatar
Alexander Ivanov committed
54

55 56 57 58
    /**
     * Activity with index of it task.
     */
    private final WeakHashMap<Activity, Integer> taskIndexes;
Alexander Ivanov's avatar
Alexander Ivanov committed
59

60 61 62 63
    /**
     * Listener for errors.
     */
    private OnErrorListener onErrorListener;
Alexander Ivanov's avatar
Alexander Ivanov committed
64

65
    private final static ActivityManager instance;
Alexander Ivanov's avatar
Alexander Ivanov committed
66

67 68 69 70
    static {
        instance = new ActivityManager();
        Application.getInstance().addManager(instance);
    }
Alexander Ivanov's avatar
Alexander Ivanov committed
71

72 73 74
    public static ActivityManager getInstance() {
        return instance;
    }
Alexander Ivanov's avatar
Alexander Ivanov committed
75

76 77 78 79 80 81
    private ActivityManager() {
        this.application = Application.getInstance();
        activities = new ArrayList<Activity>();
        nextTaskIndex = 0;
        taskIndexes = new WeakHashMap<Activity, Integer>();
    }
Alexander Ivanov's avatar
Alexander Ivanov committed
82

83 84 85 86 87 88 89 90 91
    /**
     * Removes finished activities from stask.
     */
    private void rebuildStack() {
        Iterator<Activity> iterator = activities.iterator();
        while (iterator.hasNext())
            if (iterator.next().isFinishing())
                iterator.remove();
    }
Alexander Ivanov's avatar
Alexander Ivanov committed
92

93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
    /**
     * Finish all activities in stack till the root contact list.
     *
     * @param finishRoot also finish root contact list.
     */
    public void clearStack(boolean finishRoot) {
        ContactList root = null;
        rebuildStack();
        for (Activity activity : activities) {
            if (!finishRoot && root == null && activity instanceof ContactList)
                root = (ContactList) activity;
            else
                activity.finish();
        }
        rebuildStack();
    }
Alexander Ivanov's avatar
Alexander Ivanov committed
109

110 111 112 113 114 115 116 117 118 119
    /**
     * @return Whether contact list is in the activity stack.
     */
    public boolean hasContactList(Context context) {
        rebuildStack();
        for (Activity activity : activities)
            if (activity instanceof ContactList)
                return true;
        return false;
    }
Alexander Ivanov's avatar
Alexander Ivanov committed
120

121 122 123 124 125 126 127 128
    /**
     * Apply theme settings.
     *
     * @param activity
     */
    private void applyTheme(Activity activity) {
        activity.setTheme(R.style.Theme);
    }
Alexander Ivanov's avatar
Alexander Ivanov committed
129

130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
    /**
     * Push activity to stack.
     * <p/>
     * Must be called from {@link Activity#onCreate(Bundle)}.
     *
     * @param activity
     */
    public void onCreate(Activity activity) {
        if (LOG)
            LogManager.i(activity, "onCreate: " + activity.getIntent());
        applyTheme(activity);
        if (application.isClosing() && !(activity instanceof LoadActivity)) {
            activity.startActivity(LoadActivity.createIntent(activity));
            activity.finish();
        }
        activities.add(activity);
        rebuildStack();
        fetchTaskIndex(activity, activity.getIntent());
    }
Alexander Ivanov's avatar
Alexander Ivanov committed
149

150 151 152 153 154 155 156 157 158 159 160 161
    /**
     * Pop activity from stack.
     * <p/>
     * Must be called from {@link Activity#onDestroy()}.
     *
     * @param activity
     */
    public void onDestroy(Activity activity) {
        if (LOG)
            LogManager.i(activity, "onDestroy");
        activities.remove(activity);
    }
Alexander Ivanov's avatar
Alexander Ivanov committed
162

163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
    /**
     * Pause activity.
     * <p/>
     * Must be called from {@link Activity#onPause()}.
     *
     * @param activity
     */
    public void onPause(Activity activity) {
        if (LOG)
            LogManager.i(activity, "onPause");
        if (onErrorListener != null)
            application
                    .removeUIListener(OnErrorListener.class, onErrorListener);
        onErrorListener = null;
    }
Alexander Ivanov's avatar
Alexander Ivanov committed
178

179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194
    /**
     * Resume activity.
     * <p/>
     * Must be called from {@link Activity#onResume()}.
     *
     * @param activity
     */
    public void onResume(final Activity activity) {
        if (LOG)
            LogManager.i(activity, "onResume");
        if (!application.isInitialized() && !(activity instanceof LoadActivity)) {
            if (LOG)
                LogManager.i(this, "Wait for loading");
            activity.startActivity(LoadActivity.createIntent(activity));
        }
        if (onErrorListener != null) {
195 196
            application.removeUIListener(OnErrorListener.class, onErrorListener);
        }
197 198 199 200 201 202 203 204 205
        onErrorListener = new OnErrorListener() {
            @Override
            public void onError(final int resourceId) {
                Toast.makeText(activity, activity.getString(resourceId),
                        Toast.LENGTH_LONG).show();
            }
        };
        application.addUIListener(OnErrorListener.class, onErrorListener);
    }
Alexander Ivanov's avatar
Alexander Ivanov committed
206

207 208 209 210 211 212 213 214 215 216 217 218
    /**
     * New intent received.
     * <p/>
     * Must be called from {@link Activity#onNewIntent(Intent)}.
     *
     * @param activity
     * @param intent
     */
    public void onNewIntent(Activity activity, Intent intent) {
        if (LOG)
            LogManager.i(activity, "onNewIntent: " + intent);
    }
Alexander Ivanov's avatar
Alexander Ivanov committed
219

220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235
    /**
     * Result has been received.
     * <p/>
     * Must be called from {@link Activity#onActivityResult(int, int, Intent)}.
     *
     * @param activity
     * @param requestCode
     * @param resultCode
     * @param data
     */
    public void onActivityResult(Activity activity, int requestCode,
                                 int resultCode, Intent data) {
        if (LOG)
            LogManager.i(activity, "onActivityResult: " + requestCode + ", "
                    + resultCode + ", " + data);
    }
Alexander Ivanov's avatar
Alexander Ivanov committed
236

237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252
    /**
     * Adds task index to the intent if specified for the source activity.
     * <p/>
     * Must be used when source activity starts new own activity from
     * {@link Activity#startActivity(Intent)} and
     * {@link Activity#startActivityForResult(Intent, int)}.
     *
     * @param source
     * @param intent
     */
    public void updateIntent(Activity source, Intent intent) {
        Integer index = taskIndexes.get(source);
        if (index == null)
            return;
        intent.putExtra(EXTRA_TASK_INDEX, index);
    }
Alexander Ivanov's avatar
Alexander Ivanov committed
253

254 255 256 257 258 259 260 261 262 263
    /**
     * Mark activity to be in separate activity stack.
     *
     * @param activity
     */
    public void startNewTask(Activity activity) {
        taskIndexes.put(activity, nextTaskIndex);
        LogManager.i(activity, "Start new task " + nextTaskIndex);
        nextTaskIndex += 1;
    }
Alexander Ivanov's avatar
Alexander Ivanov committed
264

265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280
    /**
     * Either move main task to back, either close all activities in subtask.
     *
     * @param activity
     */
    public void cancelTask(Activity activity) {
        Integer index = taskIndexes.get(activity);
        LogManager.i(activity, "Cancel task " + index);
        if (index == null) {
            activity.moveTaskToBack(true);
        } else {
            for (Entry<Activity, Integer> entry : taskIndexes.entrySet())
                if (entry.getValue() == index)
                    entry.getKey().finish();
        }
    }
Alexander Ivanov's avatar
Alexander Ivanov committed
281

282 283 284 285 286 287 288 289 290 291 292 293 294
    /**
     * Fetch task index from the intent and mark specified activity.
     *
     * @param activity
     * @param intent
     */
    private void fetchTaskIndex(Activity activity, Intent intent) {
        int index = intent.getIntExtra(EXTRA_TASK_INDEX, -1);
        if (index == -1)
            return;
        LogManager.i(activity, "Fetch task index " + index);
        taskIndexes.put(activity, index);
    }
Alexander Ivanov's avatar
Alexander Ivanov committed
295

296 297 298 299
    @Override
    public void onUnload() {
        clearStack(true);
    }
300

Alexander Ivanov's avatar
Alexander Ivanov committed
301
}