chrometophone (4)

今日も朝から掘削。というか右肩を動かすと痛む上に眠くて集中できぬ。

AlarmManager

これ、知りませんでした。PendingIntent も存在は知ってましたが扱うのは初めて。そりゃ良いのですが、以下の件

The REGISTRATION Intent is generated with an error parameter if the registration couldn't be completed. If that happens, the application should try again later with exponential back off.

意味不明。基本的には C2DMBaseReceiver#handleRegistration メソドの

        } else if (error != null) {
            // we are not registered, can try again
            C2DMessaging.clearRegistrationId(context);
            // Registration failed
            Log.e(TAG, "Registration error " + error);
            onError(context, error);
            if ("SERVICE_NOT_AVAILABLE".equals(error)) {
                long backoffTimeMs = C2DMessaging.getBackoff(context);
                
                Log.d(TAG, "Scheduling registration retry, backoff = " + backoffTimeMs);
                Intent retryIntent = new Intent(C2DM_RETRY);
                PendingIntent retryPIntent = PendingIntent.getBroadcast(context, 
                        0 /*requestCode*/, retryIntent, 0 /*flags*/);
                
                AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
                am.set(AlarmManager.ELAPSED_REALTIME,
                        backoffTimeMs, retryPIntent);

                // Next retry should wait longer.
                backoffTimeMs *= 2;
                C2DMessaging.setBackoff(context, backoffTimeMs);

な部分がそれに当たると思ってるんですが、com.google.android.c2dm.intent.RETRY な BroadcastIntent を掴まえる filter が見当たりません。
AndroidManifest.xml の該当部分は以下

        <receiver android:name="com.google.android.c2dm.C2DMBroadcastReceiver"
                  android:permission="com.google.android.c2dm.permission.SEND">
            <!-- Receive the actual message -->
            <intent-filter>
                <action android:name="com.google.android.c2dm.intent.RECEIVE" />
                <category android:name="com.google.android.apps.chrometophone" />
            </intent-filter>
            <!-- Receive the registration id -->
            <intent-filter>
                <action android:name="com.google.android.c2dm.intent.REGISTRATION" />
                <category android:name="com.google.android.apps.chrometophone" />
            </intent-filter>
        </receiver>

なので com.google.android.c2dm.intent.RETRY を相手にしてなさげ。ええとこれって REGISTER とか UNREGISTER とかと一緒で云々、ってオチなのかなぁ。
もう少し調べます。ってか何やってるのか < 自分

てか

よく考えたら自分で sendBroadcast して自分で受けるってのも変な話だな。あ、違うや。onHandleIntent で篩にかけてるので少なくともこの intent で startService されてるはず。

    public final void onHandleIntent(Intent intent) {
        try {
            Context context = getApplicationContext();
            if (intent.getAction().equals(REGISTRATION_CALLBACK_INTENT)) {
                handleRegistration(context, intent);
            } else if (intent.getAction().equals(C2DM_INTENT)) {
                onMessage(context, intent);
            } else if (intent.getAction().equals(C2DM_RETRY)) {
                C2DMessaging.register(context, senderId);

あーやっぱアレだ。自分で sendBroadcast して自分で受けてるわ。自分から自分なら filter 不要とかそんなルールなのかなぁ。

とゆー事で

以下な intent-filter の追加が必要って事にしとく。

            <!-- Retry sending registration -->
            <intent-filter>
                <action android:name="com.google.android.c2dm.intent.RETRY" />
                <category android:name="com.google.android.apps.chrometophone" />
            </intent-filter>

で、とりあえず C2DMBaseReceiver#handleRegistration メソドでの上記の引用部分が_exponential back off_にあたる部分になります。intent から取り出した "error" なナニが null ではなくって "SERVICE_NOT_AVAILABLE" だった場合は、との事。
ヤッてる事を以下に順に列挙。

  • C2DMessaging.getBackoff により値を取得 (初期値は 1000 とかだったりするのかどうか)
  • com.google.android.c2dm.intent.RETRY な Intent を生成
  • 上記の Intent を元に getBroadcast により PendingIntent を生成
  • Context#getSystemService メソドにより、AlarmManager なインスタンスを取得
  • AlarmManager#set メソドを上記で取得した backoff なソレ (Ms って変数名のケツに付いてました) と PendingIntent のインスタンスを渡して呼び出す
    • backoff な時間後に PendingIntent に仕込まれた Intent を sendBroadcast します
  • backoff なソレに 2 を掛けたものを C2DMessaging.setBackoff に渡す
    • backoffTime なソレは SharedPreferences に格納されている模様 (@C2DMessaging)

AlarmManager とか PendingIntent とかってはっきり理解してなかったんですが、使えますね。sendBroadcast だけではなくて、startActivity とか startService とかも範疇内らしい。