2012年11月14日水曜日

Android-4.2へバージョンアップ




Galaxy NexusおよびNexus7のOTAが開始しました。
と、いうことで早速、バージョンアップを行い動作確認を行いました。


ロック画面用Widget

新機能です。ロック画面にて左swapするとロック画面用Widgetの設定画面が現れます。




十字ボタンをクリックするとWidget選択画面が表示されます。
その際のLogはこちら。


11-13 23:33:22.010: I/ActivityManager(389): START u0 {act=android.appwidget.action.KEYGUARD_APPWIDGET_PICK flg=0x34800000 cmp=com.android.settings/.KeyguardAppWidgetPickActivity (has extras)} from pid 389
11-13 23:33:22.088: I/AppWidgetAdapter(1824): EXTRA_CUSTOM_INFO not present.
11-13 23:33:22.252: I/ActivityManager(389): Displayed com.android.settings/.KeyguardAppWidgetPickActivity: +178ms
11-13 23:33:22.260: D/YouTube(3693): youtube.app.prefetch.PrefetchStore$UserPresentReceiver.onReceive:364 Received: android.intent.action.USER_PRESENT
11-13 23:33:22.260: D/PhoneStatusBar(557): disable: < expand icons alerts ticker system_info BACK HOME recent* clock search >
11-13 23:33:22.268: D/NfcService(639): NFC-C ON
11-13 23:33:22.346: D/PhoneStatusBar(557): disable: < expand icons alerts ticker system_info back* home* recent clock search >


以下のキーワードがポイントとなるでしょう。ソースが公開されたらgrepしてみよう!
 android.appwidget.action.KEYGUARD_APPWIDGET_PICK
 KeyguardAppWidgetPickActivity



DayDream

Android公式サイトに"DayDream"なる記載があります。
 http://www.android.com/whatsnew/

この機能は、Dock装着時または充電時にスクリーンセーバーを表示させます。
設定→ディスプレイ→スクリーンセーバーから、以下の設定が可能。

  • 時計
  • カラー
  • カレント
  • フォトテーブル
  • フォトフレーム


試しにフォトテーブルを設定して、"DayDream"を起動してみました。
その際のLogはこちら。


11-14 00:06:14.061: I/PowerManagerService(389): Nap time...
11-14 00:06:14.061: I/DreamManagerService(389): Entering dreamland.
11-14 00:06:14.068: I/DreamController(389): Starting dream: name=ComponentInfo{com.android.dreams.phototable/com.android.dreams.phototable.PhotoTableDream}, isTest=false, userId=0

DreamManagerServiceというServiceが新設されているようです。

また、OTAのzipファイルの中身を覗いてみると、PhotoTable.apkというアプリが存在していました。


(つづく)

2012年10月10日水曜日

Nexus 7をandroid-4.1.2へバージョンアップ

すでにNexus 7向けのandroid-4.1.2 OTAが開始されていました。
XDAに投稿されていました。
http://forum.xda-developers.com/showthread.php?p=32587742


OTAの適用方法
rootを取っていなくてもOKです。

  1. adb reboot bootloaderを実行
  2. Recovery Mode起動
  3. apply update from ADBを選択
  4. adb sideload "OTAのfilename"を実行




標準ランチャーの横画面
いままで頑なに縦画面しか表示されなかった標準ランチャーですが、ついに横画面に対応しました。
これは便利!

2012年8月30日木曜日

Android 4.1 JellyBeanのロック画面表示中のActivityLifeCycleについて

Androidのバージョンによって、動作に差異があったのでメモ。
おそらく、Google側も省電力を気にしているのだと思います。




Android 2.3.3 GB(API Level 10) のActivityLifeCycle

電源キー押下によりScreen OFF
onPause()

電源キー押下によりScreen ON → ロック画面表示中
onResume()

ロック画面解除
※ActivityのActivityLifeCycleメソッドはコールされず

Android 4.0.X ICS(API Level 14,15) のActivityLifeCycle

電源キー押下によりScreen OFF
onPause()
 ↓
onStop()

電源キー押下によりScreen ON → ロック画面表示中
onRestart()
 ↓
onStart()
 ↓
onResume()

ロック画面解除
※ActivityのActivityLifeCycleメソッドはコールされず

Android 4.1 JellyBean(API Level 16) のActivityLifeCycle

電源キー押下によりScreen OFF
onPause()
 ↓
onStop()

電源キー押下によりScreen ON → ロック画面表示中
※ActivityのActivityLifeCycleメソッドはコールされず
ロック画面解除
onRestart()
 ↓
onStart()
 ↓
onResume()

2012年8月28日火曜日

自アプリケーションがTOPかどうか確認する方法(4)

ActivityのTaskListの順番を見るよりは、アプリケーションプロセスを見る方が正確だと思います。
ActivityManager#getRunningAppProcesses()で取得可能です。


処理:

  1. ActivityManagerから実行中プロセス情報一覧を取得
  2. 自アプリケーションが存在するかチェック
  3. プロセス情報(importance )の状態を確認する


ソースはこんな感じ。


    private void checkRunningAppProcess(){
        Log.e("","checkRunningAppProcess");

        ActivityManager am = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE);
        List<runningappprocessinfo> processInfoList = am.getRunningAppProcesses();
        for( RunningAppProcessInfo info : processInfoList){
            if(info.processName.equals(getPackageName())){
                if( info.importance == RunningAppProcessInfo.IMPORTANCE_FOREGROUND){
                    // app is FOREGROUND
                    Log.e("","app is FOREGROUND");
                }
            }
        }
    }

2012年8月27日月曜日

自アプリケーションがTOPかどうか確認する方法(3)

ActivityManager#getRecentTasks()の情報って?

getRunningTasks()と同様にgetRecentTasks()を見てみます。

ActivityManagerService#getRecentTasks()の処理をチェック。

    public List<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum,
            int flags) {
                     :
                     :
            final int N = mRecentTasks.size();
            ArrayList<ActivityManager.RecentTaskInfo> res
                    = new ArrayList<ActivityManager.RecentTaskInfo>(
                            maxNum < N ? maxNum : N);
            for (int i=0; i<N && maxNum > 0; i++) {
                     :
                     :
       

mRecentTasksのTaskRecord情報からListを生成します。

TaskRecordをmRecentTasksに追加するタイミング

ActivityManagerService#addRecentTaskLocked(TaskRecord task)でaddを行っており、
このモジュールをコールするのはActivityStackのこちら。

final boolean realStartActivityLocked()
final boolean resumeTopActivityLocked()

Activity起動、またはresumeを行ってActivityがTopになったタイミングでtaskをaddします。


TaskRecordをmRecentTasksから削除するタイミング

削除するのは以下のタイミング
addRecentTaskLocked()のadd処理でMAX(=20)を超えた場合、古いものを削除 RecentsPanelView(=履歴表示)からSwipで削除した場合、ActivityManagerService#removeTask()をコール


こちらはRunningTasksとくらべ、ユーザー操作に近いトリガーとなります。


getRecentTasks()は『起動アプリ履歴に残っているTask一覧』であって、
現在、起動中と意味でTask情報を取得したい場合はgetRunningTasks()を使用する方が好ましいと思います。

自アプリケーションがTOPかどうか確認する方法(2)

ActivityManager#getRunningTasks()の情報って?

ActivityManager#getRunningTasks()の情報が何かソースを見てみます。

モジュールを辿っていくと、ActivityManagerService#getTasks()をコールします。

ActivityManager#getRunningTasks()
- ActivityManagerService#getTasks()


ActivityManagerService#getTasks()は以下のような処理。


    public List getTasks(int maxNum, int flags,
                         IThumbnailReceiver receiver) {
        ArrayList list = new ArrayList();
                     :
                     :
            int pos = mMainStack.mHistory.size()-1;
            ActivityRecord next =
                pos >= 0 ? (ActivityRecord)mMainStack.mHistory.get(pos) : null;
            ActivityRecord top = null;
            TaskRecord curTask = null;
            int numActivities = 0;
            int numRunning = 0;
            while (pos >= 0 && maxNum > 0) {
                     :
                     :
            }
    }
mMainStack.mHistoryのActivityRecord情報からListを生成します。



ActivityRecordをmMainStack.mHistoryに追加するタイミング

mMainStack.mHistoryのadd()をコールするソースはActivityStack.java。
もともとActivityManagerServiceに記述されていたソースのうち、Stack情報に関わる操作などがActivityStack.javaに分離されました。

で、mMainStack.mHistoryのadd()をコールするのは以下のモジュール。


final boolean switchUser()
private final void startActivityLocked()
private final ActivityRecord resetTaskIfNeededLocked()
private final ActivityRecord moveActivityToFrontLocked()
final void moveTaskToFrontLocked()
final boolean moveTaskToBackLocked()
Activityをstartしたり、起動済みのActivityをFrontに移行する際に呼ばれていました。



ActivityRecordをmMainStack.mHistoryから削除するタイミング

リストから明示的に削除を行っているのは以下のモジュールです。

removeActivityFromHistoryLocked
このモジュールはActivityがDestroyされるときにコールされます。

final boolean destroyActivityLocked
つまり、アプリ内のすべてのActivityがDestroyされるとmMainStack.mHistory内から抹殺され、 (onStop状態でも)Activityが一つでも残っていればmMainStack.mHistoryに存在することとなります。

自アプリケーションがTOPかどうか確認する方法

以前の記事でApplication単位でresume/pauseのハンドリングが不可能とわかりました。
 http://baroqueworksdevjp.blogspot.jp/2012/08/applicationonterminate.html


では、他に何かいい方法がないか調べてみました。


ActivityManagerの公開APIを使う

以下のような、Task情報を取得できるAPIをActivityのonStop()でコールしてみました。
    private void checkRecentTasks(){
        Log.e("","checkRecentTasks");

        ActivityManager am = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE);
        List<RecentTaskInfo> taskInfo = am.getRecentTasks(10, ActivityManager.RECENT_WITH_EXCLUDED);
        for( RecentTaskInfo info : taskInfo){
            Log.e("", "" + info.baseIntent.getComponent().getPackageName());
        }
    }
    
    private void checkRunningTasks(){
        Log.e("","checkRunningTasks");
  
        ActivityManager am = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE);
        List<RunningTaskInfo> taskInfo = am.getRunningTasks(10);
        for( RunningTaskInfo info : taskInfo){
            Log.e("","" + info.topActivity.getPackageName());
        }
    }


Homeキー押下によりSampleアプリをBackGroudにさせたlogです。

checkRecentTasks
08-27 21:12:13.314: E/(7511): com.android.launcher
08-27 21:12:13.314: E/(7511): jp.baroqueworksdev.sampleapp
08-27 21:12:13.314: E/(7511): com.android.packageinstaller
08-27 21:12:13.314: E/(7511): jp.r246.twicca
08-27 21:12:13.314: E/(7511): com.alphonso.pulse
08-27 21:12:13.314: E/(7511): com.chnavi.android2ch
08-27 21:12:13.314: E/(7511): jp.mixi
08-27 21:12:13.314: E/(7511): com.facebook.katana
08-27 21:12:13.314: E/(7511): com.android.chrome

checkRunningTasks
08-27 21:12:13.321: E/(7511): com.android.launcher
08-27 21:12:13.321: E/(7511): jp.baroqueworksdev.sampleapp
08-27 21:12:13.321: E/(7511): jp.r246.twicca
08-27 21:12:13.321: E/(7511): com.alphonso.pulse
08-27 21:12:13.321: E/(7511): com.chnavi.android2ch
08-27 21:12:13.321: E/(7511): jp.mixi
08-27 21:12:13.321: E/(7511): com.facebook.katana
08-27 21:12:13.321: E/(7511): com.android.chrome


直近に起動したアプリ順に並んでいました。
Android Developer Siteにも以下のように書いています。
 with the most recent being first and older ones after in order.


上記のようなTaskリストを取得して、自アプリがTOPかどうかチェックするのも一つの手段かと思います。.
ただし、ロック画面が表示されている場合、TOPにいても「画面上表示されておらずユーザーには見えない」ことを忘れずに。