Androidのタスク一覧について


※Android4.4系を対象にしたアプリ開発のメモになります。現在は変わっている可能性が高いです。

1年前にAndroidアプリを開発していた際に、Push機能やらなにやらの追加で起動後のActivityが意図しない物に変わっていた。
これは起動時のIntentやアプリの状況(バックグラウンドに存在するか否か)が関係していて、余計なIntentFlagを排除する処理を加えて強引に解決した記憶がある。

その際にタスク一覧から起動した時とホーム画面のアイコンから起動した時、Pushから起動したときなど、色々なケースでActivityを起動し、ActivityやIntentFlagについて調べたものがこちらになる。

開発から離れてしまったが、その時のメモが残っていたので供養を兼ねて公開しておく。


参考にしたページ

* IntentのCategoryとExtraとFlagの一覧表を作ってみたよ - hyoromoのブログ http://hyoromo.hatenablog.com/entry/20091003/1254590170
Intent | Android Developers http://developer.android.com/intl/ja/reference/android/content/Intent.html
* GC: RecentsPanelView - com.android.systemui.recent.RecentsPanelView (.java) - GrepCode Class Source http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.2_r1/com/android/systemui/recent/RecentsPanelView.java#RecentsPanelView.simulateClick%28int%29
* GC: ActivityManager - android.app.ActivityManager (.java) - GrepCode Class Source http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.2_r1/android/app/ActivityManager.java#ActivityManager.setFrontActivityScreenCompatMode%28int%29
* GC: PendingIntent - android.app.PendingIntent (.java) - GrepCode Class Source http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.4.4_r1/android/app/PendingIntent.java#PendingIntent.send%28android.content.Context%2Cint%2Candroid.content.Intent%2Candroid.app.PendingIntent.OnFinished%2Candroid.os.Handler%29


# タスク一覧について
* ActivityManagerというのが走ってる
	* ホーム画面（com.sonyericsson.home/com.sonymobile.home.HomeActivity）などに遷移する際に、コイツからIntentが投げられてるっぽい
	* ホームボタン押下時
		ActivityManager﹕ START u0 {act=android.intent.action.MAIN cat=[android.intent.category.HOME] flg=0x10200000 cmp=com.sonyericsson.home/com.sonymobile.home.HomeActivity}
	* アプリアイコンから起動時
		ActivityManager﹕ START u0 {act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=jp.co.my.application/.screen.splash.SplashActivity}
* ホームアイコンからはaction.MAIN,category.HOMEのIntentが発行されてアプリが起動
* タスク一覧からの起動
	* ActivityManager﹕ START u0 {act=com.android.systemui.recent.action.TOGGLE_RECENTS flg=0x10800000 cmp=com.android.systemui/.recent.RecentsActivity
		* RecentsActivityというActivityが管理してるっぽい

# RecentsActivityについて
* RecentsPanelViewというListViewっぽいのを持ってて、ApplicationId(taskId)とかサムネを持ってるのでタスク一覧はこれっぽい
* RecentsPanelViewのアイテムが選択(handleOnClick)されると、ActivityManagerから該当するtaskIdを持つアプリをフォアグラウンドにするっぽい
（moveTaskToFront(int taskId, int flags, Bundle options) というメソッドが呼ばれる）
	* バックグラウンドで動作しているかによって呼ばれるのは異なる
		* していない場合はActivityManagerの持つIntentを使ってアプリを起動
		* その時のフラグとかはこんな感じ
intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY| Intent.FLAG_ACTIVITY_TASK_ON_HOME| Intent.FLAG_ACTIVITY_NEW_TASK)
		* 新規に開始する場合はログが出る（Log.v(TAG, "Starting activity " + intent)）
		
* ActivityManagerのRecentTaskInfoクラスがParcelable...
	* もちろんIntent持ってる


# 起動時のIntentについて検めて見た
## アプリアイコンから起動
V/SplashActivity﹕ Intent[@45c1c288] content:
V/SplashActivity﹕ Action   : android.intent.action.MAIN
V/SplashActivity﹕ Category : {android.intent.category.LAUNCHER}
V/SplashActivity﹕ Data     : null
V/SplashActivity﹕ Component: jp.co.my.application/jp.co.my.application.screen.splash.SplashActivity
V/SplashActivity﹕ Flags    : 10000001000000000000000000000
V/SplashActivity﹕ Flag     : FLAG_RECEIVER_FOREGROUND
V/SplashActivity﹕ Flag     : FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
V/SplashActivity﹕ HasExtras: false

### MainActivityに遷移
V/MainActivity﹕ Intent[@45c8fef8] content:
V/MainActivity﹕ Action   : null
V/MainActivity﹕ Category : null
V/MainActivity﹕ Data     : null
V/MainActivity﹕ Component: jp.co.my.application/jp.co.my.application.screen.main.controller.MainActivity
V/MainActivity﹕ Flags    : 0
V/MainActivity﹕ HasExtras: false

## タスク一覧から起動
V/SplashActivity﹕ Intent[@45c4f890] content:
V/SplashActivity﹕ Action   : android.intent.action.MAIN
V/SplashActivity﹕ Category : {android.intent.category.LAUNCHER}
V/SplashActivity﹕ Data     : null
V/SplashActivity﹕ Component: jp.co.my.application/jp.co.my.application.screen.splash.SplashActivity
V/SplashActivity﹕ Flags    : 10000000100000100000000000000
V/SplashActivity﹕ Flag     : FLAG_ACTIVITY_TASK_ON_HOME
V/SplashActivity﹕ Flag     : FLAG_RECEIVER_FOREGROUND
V/SplashActivity﹕ Flag     : FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY
V/SplashActivity﹕ HasExtras: false

## 2回め
V/SplashActivity﹕ Intent[@45743a58] content:
V/SplashActivity﹕ Action   : android.intent.action.MAIN
V/SplashActivity﹕ Category : {android.intent.category.LAUNCHER}
V/SplashActivity﹕ Data     : null
V/SplashActivity﹕ Component: jp.co.my.application/jp.co.my.application.screen.splash.SplashActivity
V/SplashActivity﹕ Flags    : 10000001100000100000000000000
V/SplashActivity﹕ Flag     : FLAG_ACTIVITY_TASK_ON_HOME
V/SplashActivity﹕ Flag     : FLAG_RECEIVER_FOREGROUND
V/SplashActivity﹕ Flag     : FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY
V/SplashActivity﹕ Flag     : FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
V/SplashActivity﹕ HasExtras: false

### MainActivityに遷移
V/MainActivity﹕ Intent[@4590bff0] content:
V/MainActivity﹕ Action   : null
V/MainActivity﹕ Category : null
V/MainActivity﹕ Data     : null
V/MainActivity﹕ Component: jp.co.my.application/jp.co.my.application.screen.main.controller.MainActivity
V/MainActivity﹕ Flags    : 0
V/MainActivity﹕ HasExtras: false
V/MainActivity﹕ Flags    : 0

## バックグラウンドに居ない時
V/SplashActivity﹕ Intent[@426ca1c0] content:
V/SplashActivity﹕ Action   : android.intent.action.MAIN
V/SplashActivity﹕ Category : {android.intent.category.LAUNCHER}
V/SplashActivity﹕ Data     : null
V/SplashActivity﹕ Component: jp.co.my.application/jp.co.my.application.screen.splash.SplashActivity
V/SplashActivity﹕ Flags    : 10000001000000000000000000000
V/SplashActivity﹕ Flag     : FLAG_RECEIVER_FOREGROUND
V/SplashActivity﹕ Flag     : FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
V/SplashActivity﹕ HasExtras: false


## Pushの開封
D/MyApplication﹕ [MainActivity#onCreate:64] : ---init----
V/MainActivity﹕ Intent[@45e7a560] content:
V/MainActivity﹕ Action   : null
V/MainActivity﹕ Category : null
V/MainActivity﹕ Data     : null
V/MainActivity﹕ Component: jp.co.my.application/jp.co.my.application.screen.main.controller.MainActivity
V/MainActivity﹕ Flags    : 10000000000001000000000000000
V/MainActivity﹕ Flag     : FLAG_ACTIVITY_CLEAR_TASK
V/MainActivity﹕ Flag     : FLAG_RECEIVER_FOREGROUND
V/MainActivity﹕ HasExtras: true
V/MainActivity﹕ Extra[push_action] :jp.co.my.application.common.model.PushObject@458edf90

### 開封後にタスク一覧から起動
V/MainActivity﹕ Intent[@45898af8] content:
V/MainActivity﹕ Action   : null
V/MainActivity﹕ Category : null
V/MainActivity﹕ Data     : null
V/MainActivity﹕ Component: jp.co.my.application/jp.co.my.application.screen.main.controller.MainActivity
V/MainActivity﹕ Flags    : 10000000100001100000000000000
V/MainActivity﹕ Flag     : FLAG_ACTIVITY_TASK_ON_HOME
V/MainActivity﹕ Flag     : FLAG_ACTIVITY_CLEAR_TASK
V/MainActivity﹕ Flag     : FLAG_RECEIVER_FOREGROUND
V/MainActivity﹕ Flag     : FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY
V/MainActivity﹕ HasExtras: true
V/MainActivity﹕ Extra[push_action] :jp.co.my.application.common.model.PushObject@45bd6480

## タスク一覧に居ない場合のPushの開封
V/MainActivity﹕ Intent[@44c13d98] content:
V/MainActivity﹕ Action   : null
V/MainActivity﹕ Category : null
V/MainActivity﹕ Data     : null
V/MainActivity﹕ Component: jp.co.my.application/jp.co.my.application.screen.main.controller.MainActivity
V/MainActivity﹕ Flags    : 10000000000001000000000000000
V/MainActivity﹕ Flag     : FLAG_ACTIVITY_CLEAR_TASK
V/MainActivity﹕ Flag     : FLAG_RECEIVER_FOREGROUND
V/MainActivity﹕ HasExtras: true
V/MainActivity﹕ Extra[push_action] :jp.co.my.application.common.model.PushObject@44d730b8



## まとめ

* MainActivityがPush開封後にタスク一覧から起動する場合、意図しない遷移が発生する
	* IntentにPushを受け取った時に作成したIntentが残っている
	* Push開封後のタスク一覧から起動のIntentには、FLAG_ACTIVITY_LAUNCHED_FROM_HISTORYとFLAG_ACTIVITY_TASK_ON_HOMEが増えている
	* Pushに関係ない場合のタスク一覧から起動した場合もこれらのFlagが付与されているので、一覧から起動したときの挙動と思われ(主にFROM_HISTORY)
	* Push開封のIntent処理の際に、このFlagでifすれば対処は可能と思われる