am 8188f826: Merge "Multiple fixes to CMAS app." into jb-mr1-dev
* commit '8188f826ab8573d3c08566c61d0708f465115a78':
Multiple fixes to CMAS app.
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 3294be5..9b60968 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -49,7 +49,7 @@
<activity android:name="CellBroadcastListActivity"
android:label="@string/app_label"
android:configChanges="orientation|keyboardHidden"
- android:launchMode="singleTop">
+ android:launchMode="singleTask">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<!-- Uncomment this category to show the Cell Broadcasts launcher icon.
@@ -65,14 +65,15 @@
</intent-filter>
</activity>
+ <!-- Settings opened by ListActivity menu, Settings app link or opt-out dialog. -->
<activity android:name="CellBroadcastSettings"
android:label="@string/sms_cb_settings"
+ android:launchMode="singleTask"
android:exported="true" />
<activity android:name="CellBroadcastAlertDialog"
- android:excludeFromRecents="true"
android:theme="@android:style/Theme.Holo.Dialog"
- android:launchMode="singleInstance"
+ android:launchMode="singleTask"
android:exported="false"
android:configChanges="orientation|keyboardHidden|keyboard|navigation" />
@@ -80,10 +81,14 @@
<activity android:name="CellBroadcastAlertFullScreen"
android:excludeFromRecents="true"
android:theme="@style/AlertFullScreenTheme"
- android:launchMode="singleInstance"
+ android:launchMode="singleTask"
android:exported="false"
android:configChanges="orientation|keyboardHidden|keyboard|navigation" />
+ <!-- Container activity for CMAS opt-in/opt-out dialog. -->
+ <activity android:name="CellBroadcastOptOutActivity"
+ android:exported="false" />
+
<!-- Require sender permissions to prevent SMS spoofing -->
<receiver android:name="PrivilegedCellBroadcastReceiver"
android:permission="android.permission.BROADCAST_SMS">
diff --git a/res/values/strings.xml b/res/values/strings.xml
index e3714ba..0a9b387 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -213,6 +213,18 @@
<!-- Non-emergency broadcast notification title for multiple unread alerts. -->
<string name="notification_multiple_title">New alerts</string>
+ <!-- Show CMAS opt-out dialog on first non-Presidential alert. [CHAR LIMIT=100] -->
+ <string name="show_cmas_opt_out_summary">Show an opt-out dialog after displaying the first CMAS alert (other than Presidential Alert).</string>
+ <!-- Show CMAS opt-out dialog on first non-Presidential alert. [CHAR LIMIT=40] -->
+ <string name="show_cmas_opt_out_title">Show opt-out dialog</string>
+
+ <!-- CMAS opt-out dialog message. [CHAR LIMIT=160] -->
+ <string name="cmas_opt_out_dialog_text">You are currently receiving Emergency Alerts. Would you like to continue receiving Emergency Alerts?</string>
+ <!-- Text for positive button in CMAS opt-out dialog. [CHAR LIMIT=25] -->
+ <string name="cmas_opt_out_button_yes">Yes</string>
+ <!-- Text for negative button in CMAS opt-out dialog. [CHAR LIMIT=25] -->
+ <string name="cmas_opt_out_button_no">No</string>
+
<!-- Entries listed in the ListPreference for allowed alert durations. [CHAR LIMIT=30] -->
<string-array name="alert_sound_duration_entries">
<item>2 seconds</item>
diff --git a/res/xml/preferences.xml b/res/xml/preferences.xml
index 5c29f08..340830a 100644
--- a/res/xml/preferences.xml
+++ b/res/xml/preferences.xml
@@ -96,6 +96,11 @@
android:summary="@string/enable_cmas_test_alerts_summary"
android:title="@string/enable_cmas_test_alerts_title" />
+ <CheckBoxPreference android:defaultValue="true"
+ android:key="show_cmas_opt_out_dialog"
+ android:summary="@string/show_cmas_opt_out_summary"
+ android:title="@string/show_cmas_opt_out_title" />
+
</PreferenceCategory>
</PreferenceScreen>
diff --git a/src/com/android/cellbroadcastreceiver/CellBroadcastAlertAudio.java b/src/com/android/cellbroadcastreceiver/CellBroadcastAlertAudio.java
index 2b9dabc..bc44ed1 100644
--- a/src/com/android/cellbroadcastreceiver/CellBroadcastAlertAudio.java
+++ b/src/com/android/cellbroadcastreceiver/CellBroadcastAlertAudio.java
@@ -27,7 +27,6 @@
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
-import android.os.PowerManager;
import android.os.Vibrator;
import android.speech.tts.TextToSpeech;
import android.telephony.PhoneStateListener;
@@ -76,9 +75,6 @@
private static final long[] sVibratePattern = { 0, 2000, 500, 1000, 500, 1000, 500,
2000, 500, 1000, 500, 1000};
- /** CPU wake lock while playing audio. */
- private PowerManager.WakeLock mWakeLock;
-
private static final int STATE_IDLE = 0;
private static final int STATE_ALERTING = 1;
private static final int STATE_PAUSING = 2;
@@ -199,11 +195,6 @@
@Override
public void onCreate() {
- // acquire CPU wake lock while playing audio
- PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
- mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
- mWakeLock.acquire();
-
mVibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
// Listen for incoming calls to kill the alarm.
@@ -228,8 +219,8 @@
Log.e(TAG, "exception trying to shutdown text-to-speech");
}
}
- // release CPU wake lock
- mWakeLock.release();
+ // release CPU wake lock acquired by CellBroadcastAlertService
+ CellBroadcastAlertWakeLock.releaseCpuLock();
}
@Override
diff --git a/src/com/android/cellbroadcastreceiver/CellBroadcastAlertDialog.java b/src/com/android/cellbroadcastreceiver/CellBroadcastAlertDialog.java
index 3be8439..f250928 100644
--- a/src/com/android/cellbroadcastreceiver/CellBroadcastAlertDialog.java
+++ b/src/com/android/cellbroadcastreceiver/CellBroadcastAlertDialog.java
@@ -45,7 +45,7 @@
// Listen for the screen turning off so that when the screen comes back
// on, the user does not need to unlock the phone to dismiss the alert.
- if (mMessage.isEmergencyAlertMessage()) {
+ if (CellBroadcastConfigService.isEmergencyAlertMessage(getLatestMessage())) {
mScreenOffReceiver = new ScreenOffReceiver();
registerReceiver(mScreenOffReceiver,
new IntentFilter(Intent.ACTION_SCREEN_OFF));
@@ -74,8 +74,8 @@
private void handleScreenOff() {
// Launch the full screen activity but do not turn the screen on.
Intent i = new Intent(this, CellBroadcastAlertFullScreen.class);
- i.putExtra(CellBroadcastMessage.SMS_CB_MESSAGE_EXTRA, mMessage);
- i.putExtra(SCREEN_OFF, true);
+ i.putParcelableArrayListExtra(CellBroadcastMessage.SMS_CB_MESSAGE_EXTRA, mMessageList);
+ i.putExtra(SCREEN_OFF_EXTRA, true);
startActivity(i);
finish();
}
diff --git a/src/com/android/cellbroadcastreceiver/CellBroadcastAlertFullScreen.java b/src/com/android/cellbroadcastreceiver/CellBroadcastAlertFullScreen.java
index 9940426..cf6d7e5 100644
--- a/src/com/android/cellbroadcastreceiver/CellBroadcastAlertFullScreen.java
+++ b/src/com/android/cellbroadcastreceiver/CellBroadcastAlertFullScreen.java
@@ -17,15 +17,21 @@
package com.android.cellbroadcastreceiver;
import android.app.Activity;
+import android.app.KeyguardManager;
import android.app.NotificationManager;
import android.content.Context;
import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
+import android.preference.PreferenceManager;
import android.provider.Telephony;
import android.telephony.CellBroadcastMessage;
+import android.telephony.SmsCbCmasInfo;
+import android.util.Log;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
@@ -35,24 +41,31 @@
import android.widget.ImageView;
import android.widget.TextView;
+import java.util.ArrayList;
+import java.util.concurrent.atomic.AtomicInteger;
+
/**
* Full-screen emergency alert with flashing warning icon.
* Alert audio and text-to-speech handled by {@link CellBroadcastAlertAudio}.
* Keyguard handling based on {@code AlarmAlertFullScreen} class from DeskClock app.
*/
public class CellBroadcastAlertFullScreen extends Activity {
+ private static final String TAG = "CellBroadcastAlertFullScreen";
/**
* Intent extra for full screen alert launched from dialog subclass as a result of the
* screen turning off.
*/
- static final String SCREEN_OFF = "screen_off";
+ static final String SCREEN_OFF_EXTRA = "screen_off";
- /** Whether to show the flashing warning icon. */
- private boolean mIsEmergencyAlert;
+ /** Intent extra for non-emergency alerts sent when user selects the notification. */
+ static final String FROM_NOTIFICATION_EXTRA = "from_notification";
- /** The cell broadcast message to display. */
- CellBroadcastMessage mMessage;
+ /** List of cell broadcast messages to display (oldest to newest). */
+ ArrayList<CellBroadcastMessage> mMessageList;
+
+ /** Whether a CMAS alert other than Presidential Alert was displayed. */
+ private boolean mShowOptOutDialog;
/** Length of time for the warning icon to be visible. */
private static final int WARNING_ICON_ON_DURATION_MSEC = 800;
@@ -60,37 +73,172 @@
/** Length of time for the warning icon to be off. */
private static final int WARNING_ICON_OFF_DURATION_MSEC = 800;
- /** Warning icon state. false = visible, true = off */
- private boolean mIconAnimationState;
+ /** Length of time to keep the screen turned on. */
+ private static final int KEEP_SCREEN_ON_DURATION_MSEC = 60000;
- /** Stop animating icon after {@link #onStop()} is called. */
- private boolean mStopAnimation;
+ /** Animation handler for the flashing warning icon (emergency alerts only). */
+ private final AnimationHandler mAnimationHandler = new AnimationHandler();
- /** The warning icon Drawable. */
- private Drawable mWarningIcon;
+ /** Handler to add and remove screen on flags for emergency alerts. */
+ private final ScreenOffHandler mScreenOffHandler = new ScreenOffHandler();
- /** The View containing the warning icon. */
- private ImageView mWarningIconView;
+ /**
+ * Animation handler for the flashing warning icon (emergency alerts only).
+ */
+ private class AnimationHandler extends Handler {
+ /** Latest {@code message.what} value for detecting old messages. */
+ private final AtomicInteger mCount = new AtomicInteger();
- /** Icon animation handler for flashing warning alerts. */
- private final Handler mAnimationHandler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- if (mIconAnimationState) {
- mWarningIconView.setImageAlpha(255);
- if (!mStopAnimation) {
- mAnimationHandler.sendEmptyMessageDelayed(0, WARNING_ICON_ON_DURATION_MSEC);
- }
- } else {
- mWarningIconView.setImageAlpha(0);
- if (!mStopAnimation) {
- mAnimationHandler.sendEmptyMessageDelayed(0, WARNING_ICON_OFF_DURATION_MSEC);
- }
+ /** Warning icon state: visible == true, hidden == false. */
+ private boolean mWarningIconVisible;
+
+ /** The warning icon Drawable. */
+ private Drawable mWarningIcon;
+
+ /** The View containing the warning icon. */
+ private ImageView mWarningIconView;
+
+ /** Package local constructor (called from outer class). */
+ AnimationHandler() {}
+
+ /** Start the warning icon animation. */
+ void startIconAnimation() {
+ if (!initDrawableAndImageView()) {
+ return; // init failure
}
- mIconAnimationState = !mIconAnimationState;
+ mWarningIconVisible = true;
+ mWarningIconView.setVisibility(View.VISIBLE);
+ updateIconState();
+ queueAnimateMessage();
+ }
+
+ /** Stop the warning icon animation. */
+ void stopIconAnimation() {
+ // Increment the counter so the handler will ignore the next message.
+ mCount.incrementAndGet();
+ if (mWarningIconView != null) {
+ mWarningIconView.setVisibility(View.GONE);
+ }
+ }
+
+ /** Update the visibility of the warning icon. */
+ private void updateIconState() {
+ mWarningIconView.setImageAlpha(mWarningIconVisible ? 255 : 0);
mWarningIconView.invalidateDrawable(mWarningIcon);
}
- };
+
+ /** Queue a message to animate the warning icon. */
+ private void queueAnimateMessage() {
+ int msgWhat = mCount.incrementAndGet();
+ sendEmptyMessageDelayed(msgWhat, mWarningIconVisible ? WARNING_ICON_ON_DURATION_MSEC
+ : WARNING_ICON_OFF_DURATION_MSEC);
+ // Log.d(TAG, "queued animation message id = " + msgWhat);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ if (msg.what == mCount.get()) {
+ mWarningIconVisible = !mWarningIconVisible;
+ updateIconState();
+ queueAnimateMessage();
+ }
+ }
+
+ /**
+ * Initialize the Drawable and ImageView fields.
+ * @return true if successful; false if any field failed to initialize
+ */
+ private boolean initDrawableAndImageView() {
+ if (mWarningIcon == null) {
+ try {
+ mWarningIcon = getResources().getDrawable(R.drawable.ic_warning_large);
+ } catch (Resources.NotFoundException e) {
+ Log.e(TAG, "warning icon resource not found", e);
+ return false;
+ }
+ }
+ if (mWarningIconView == null) {
+ mWarningIconView = (ImageView) findViewById(R.id.icon);
+ if (mWarningIconView != null) {
+ mWarningIconView.setImageDrawable(mWarningIcon);
+ } else {
+ Log.e(TAG, "failed to get ImageView for warning icon");
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+
+ /**
+ * Handler to add {@code FLAG_KEEP_SCREEN_ON} for emergency alerts. After a short delay,
+ * remove the flag so the screen can turn off to conserve the battery.
+ */
+ private class ScreenOffHandler extends Handler {
+ /** Latest {@code message.what} value for detecting old messages. */
+ private final AtomicInteger mCount = new AtomicInteger();
+
+ /** Package local constructor (called from outer class). */
+ ScreenOffHandler() {}
+
+ /** Add screen on window flags and queue a delayed message to remove them later. */
+ void startScreenOnTimer() {
+ addWindowFlags();
+ int msgWhat = mCount.incrementAndGet();
+ removeMessages(msgWhat - 1); // Remove previous message, if any.
+ sendEmptyMessageDelayed(msgWhat, KEEP_SCREEN_ON_DURATION_MSEC);
+ Log.d(TAG, "added FLAG_KEEP_SCREEN_ON, queued screen off message id " + msgWhat);
+ }
+
+ /** Remove the screen on window flags and any queued screen off message. */
+ void stopScreenOnTimer() {
+ removeMessages(mCount.get());
+ clearWindowFlags();
+ }
+
+ /** Set the screen on window flags. */
+ private void addWindowFlags() {
+ getWindow().addFlags(WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
+ | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+ }
+
+ /** Clear the screen on window flags. */
+ private void clearWindowFlags() {
+ getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
+ | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ int msgWhat = msg.what;
+ if (msgWhat == mCount.get()) {
+ clearWindowFlags();
+ Log.d(TAG, "removed FLAG_KEEP_SCREEN_ON with id " + msgWhat);
+ } else {
+ Log.e(TAG, "discarding screen off message with id " + msgWhat);
+ }
+ }
+ }
+
+ /** Returns the currently displayed message. */
+ CellBroadcastMessage getLatestMessage() {
+ int index = mMessageList.size() - 1;
+ if (index >= 0) {
+ return mMessageList.get(index);
+ } else {
+ return null;
+ }
+ }
+
+ /** Removes and returns the currently displayed message. */
+ private CellBroadcastMessage removeLatestMessage() {
+ int index = mMessageList.size() - 1;
+ if (index >= 0) {
+ return mMessageList.remove(index);
+ } else {
+ return null;
+ }
+ }
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -106,72 +254,131 @@
| WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
| WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
- // Turn on the screen unless we're being launched from the dialog subclass as a result of
- // the screen turning off.
- if (!getIntent().getBooleanExtra(SCREEN_OFF, false)) {
- win.addFlags(WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
- | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
- }
-
- // Save message for passing from dialog to fullscreen activity, and for marking read.
- mMessage = getIntent().getParcelableExtra(
- CellBroadcastMessage.SMS_CB_MESSAGE_EXTRA);
-
- updateLayout(mMessage);
- }
-
- protected int getLayoutResId() {
- return R.layout.cell_broadcast_alert_fullscreen;
- }
-
- private void updateLayout(CellBroadcastMessage message) {
+ // Initialize the view.
LayoutInflater inflater = LayoutInflater.from(this);
-
setContentView(inflater.inflate(getLayoutResId(), null));
- /* Initialize dialog text from alert message. */
- int titleId = CellBroadcastResources.getDialogTitleResource(message);
- setTitle(titleId);
- ((TextView) findViewById(R.id.alertTitle)).setText(titleId);
- ((TextView) findViewById(R.id.message)).setText(message.getMessageBody());
-
- /* dismiss button: close notification */
findViewById(R.id.dismissButton).setOnClickListener(
new Button.OnClickListener() {
+ @Override
public void onClick(View v) {
dismiss();
}
});
- mIsEmergencyAlert = message.isPublicAlertMessage() || CellBroadcastConfigService
- .isOperatorDefinedEmergencyId(message.getServiceCategory());
+ // Get message list from saved Bundle or from Intent.
+ if (savedInstanceState != null) {
+ Log.d(TAG, "onCreate getting message list from saved instance state");
+ mMessageList = savedInstanceState.getParcelableArrayList(
+ CellBroadcastMessage.SMS_CB_MESSAGE_EXTRA);
+ } else {
+ Log.d(TAG, "onCreate getting message list from intent");
+ Intent intent = getIntent();
+ mMessageList = intent.getParcelableArrayListExtra(
+ CellBroadcastMessage.SMS_CB_MESSAGE_EXTRA);
- if (mIsEmergencyAlert) {
- mWarningIcon = getResources().getDrawable(R.drawable.ic_warning_large);
- mWarningIconView = (ImageView) findViewById(R.id.icon);
- if (mWarningIconView != null) {
- mWarningIconView.setImageDrawable(mWarningIcon);
- }
-
- // Dismiss the notification that brought us here
- ((NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE))
- .cancel((int) message.getDeliveryTime());
+ // If we were started from a notification, dismiss it.
+ clearNotification(intent);
}
+
+ if (mMessageList != null) {
+ Log.d(TAG, "onCreate loaded message list of size " + mMessageList.size());
+ } else {
+ Log.e(TAG, "onCreate failed to get message list from saved Bundle");
+ finish();
+ }
+
+ // For emergency alerts, keep screen on so the user can read it, unless this is a
+ // full screen alert created by CellBroadcastAlertDialog when the screen turned off.
+ CellBroadcastMessage message = getLatestMessage();
+ if (CellBroadcastConfigService.isEmergencyAlertMessage(message) &&
+ (savedInstanceState != null ||
+ !getIntent().getBooleanExtra(SCREEN_OFF_EXTRA, false))) {
+ Log.d(TAG, "onCreate setting screen on timer for emergency alert");
+ mScreenOffHandler.startScreenOnTimer();
+ }
+
+ updateAlertText(message);
+ }
+
+ /**
+ * Called by {@link CellBroadcastAlertService} to add a new alert to the stack.
+ * @param intent The new intent containing one or more {@link CellBroadcastMessage}s.
+ */
+ @Override
+ protected void onNewIntent(Intent intent) {
+ ArrayList<CellBroadcastMessage> newMessageList = intent.getParcelableArrayListExtra(
+ CellBroadcastMessage.SMS_CB_MESSAGE_EXTRA);
+ if (newMessageList != null) {
+ Log.d(TAG, "onNewIntent called with message list of size " + newMessageList.size());
+ mMessageList.addAll(newMessageList);
+ updateAlertText(getLatestMessage());
+ // If the new intent was sent from a notification, dismiss it.
+ clearNotification(intent);
+ } else {
+ Log.e(TAG, "onNewIntent called without SMS_CB_MESSAGE_EXTRA, ignoring");
+ }
+ }
+
+ /** Try to cancel any notification that may have started this activity. */
+ private void clearNotification(Intent intent) {
+ if (intent.getBooleanExtra(FROM_NOTIFICATION_EXTRA, false)) {
+ Log.d(TAG, "Dismissing notification");
+ NotificationManager notificationManager =
+ (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
+ notificationManager.cancel(CellBroadcastAlertService.NOTIFICATION_ID);
+ CellBroadcastReceiverApp.clearNewMessageList();
+ }
+ }
+
+ /**
+ * Save the list of messages so the state can be restored later.
+ * @param outState Bundle in which to place the saved state.
+ */
+ @Override
+ protected void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ outState.putParcelableArrayList(CellBroadcastMessage.SMS_CB_MESSAGE_EXTRA, mMessageList);
+ Log.d(TAG, "onSaveInstanceState saved message list to bundle");
+ }
+
+ /** Returns the resource ID for either the full screen or dialog layout. */
+ protected int getLayoutResId() {
+ return R.layout.cell_broadcast_alert_fullscreen;
+ }
+
+ /** Update alert text when a new emergency alert arrives. */
+ private void updateAlertText(CellBroadcastMessage message) {
+ int titleId = CellBroadcastResources.getDialogTitleResource(message);
+ setTitle(titleId);
+ ((TextView) findViewById(R.id.alertTitle)).setText(titleId);
+ ((TextView) findViewById(R.id.message)).setText(message.getMessageBody());
}
/**
* Start animating warning icon.
*/
@Override
- protected void onStart() {
- super.onStart();
- if (mIsEmergencyAlert) {
- // start icon animation
- mAnimationHandler.sendEmptyMessageDelayed(0, WARNING_ICON_ON_DURATION_MSEC);
+ protected void onResume() {
+ Log.d(TAG, "onResume called");
+ super.onResume();
+ CellBroadcastMessage message = getLatestMessage();
+ if (message != null && CellBroadcastConfigService.isEmergencyAlertMessage(message)) {
+ mAnimationHandler.startIconAnimation();
}
}
/**
+ * Stop animating warning icon.
+ */
+ @Override
+ protected void onPause() {
+ Log.d(TAG, "onPause called");
+ mAnimationHandler.stopIconAnimation();
+ super.onPause();
+ }
+
+ /**
* Stop animating warning icon and stop the {@link CellBroadcastAlertAudio}
* service if necessary.
*/
@@ -179,7 +386,15 @@
// Stop playing alert sound/vibration/speech (if started)
stopService(new Intent(this, CellBroadcastAlertAudio.class));
- final long deliveryTime = mMessage.getDeliveryTime();
+ // Remove the current alert message from the list.
+ CellBroadcastMessage lastMessage = removeLatestMessage();
+ if (lastMessage == null) {
+ Log.e(TAG, "dismiss() called with empty message list!");
+ return;
+ }
+
+ // Mark the alert as read.
+ final long deliveryTime = lastMessage.getDeliveryTime();
// Mark broadcast as read on a background thread.
new CellBroadcastContentProvider.AsyncCellBroadcastTask(getContentResolver())
@@ -191,19 +406,55 @@
}
});
- if (mIsEmergencyAlert) {
- // stop animating emergency alert icon
- mStopAnimation = true;
- } else {
- // decrement unread non-emergency alert count
- CellBroadcastReceiverApp.decrementUnreadAlertCount();
+ // Set the opt-out dialog flag if this is a CMAS alert (other than Presidential Alert).
+ if (lastMessage.isCmasMessage() && lastMessage.getCmasMessageClass() !=
+ SmsCbCmasInfo.CMAS_CLASS_PRESIDENTIAL_LEVEL_ALERT) {
+ mShowOptOutDialog = true;
}
+
+ // If there are older emergency alerts to display, update the alert text and return.
+ CellBroadcastMessage nextMessage = getLatestMessage();
+ if (nextMessage != null) {
+ updateAlertText(nextMessage);
+ if (CellBroadcastConfigService.isEmergencyAlertMessage(nextMessage)) {
+ mAnimationHandler.startIconAnimation();
+ } else {
+ mAnimationHandler.stopIconAnimation();
+ }
+ return;
+ }
+
+ // Remove pending screen-off messages (animation messages are removed in onPause()).
+ mScreenOffHandler.stopScreenOnTimer();
+
+ // Show opt-in/opt-out dialog when the first CMAS alert is received.
+ if (mShowOptOutDialog) {
+ SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
+ if (prefs.getBoolean(CellBroadcastSettings.KEY_SHOW_CMAS_OPT_OUT_DIALOG, true)) {
+ // Clear the flag so the user will only see the opt-out dialog once.
+ prefs.edit().putBoolean(CellBroadcastSettings.KEY_SHOW_CMAS_OPT_OUT_DIALOG, false)
+ .apply();
+
+ KeyguardManager km = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
+ if (km.inKeyguardRestrictedInputMode()) {
+ Log.d(TAG, "Showing opt-out dialog in new activity (secure keyguard)");
+ Intent intent = new Intent(this, CellBroadcastOptOutActivity.class);
+ startActivity(intent);
+ } else {
+ Log.d(TAG, "Showing opt-out dialog in current activity");
+ CellBroadcastOptOutActivity.showOptOutDialog(this);
+ return; // don't call finish() until user dismisses the dialog
+ }
+ }
+ }
+
finish();
}
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
- if (!mMessage.isEtwsMessage()) {
+ CellBroadcastMessage message = getLatestMessage();
+ if (message != null && !message.isEtwsMessage()) {
switch (event.getKeyCode()) {
// Volume keys and camera keys mute the alert sound/vibration (except ETWS).
case KeyEvent.KEYCODE_VOLUME_UP:
diff --git a/src/com/android/cellbroadcastreceiver/CellBroadcastAlertService.java b/src/com/android/cellbroadcastreceiver/CellBroadcastAlertService.java
index 04fea0f..07e1bfb 100644
--- a/src/com/android/cellbroadcastreceiver/CellBroadcastAlertService.java
+++ b/src/com/android/cellbroadcastreceiver/CellBroadcastAlertService.java
@@ -26,7 +26,6 @@
import android.content.SharedPreferences;
import android.os.Bundle;
import android.os.IBinder;
-import android.os.PowerManager;
import android.preference.PreferenceManager;
import android.provider.Telephony;
import android.telephony.CellBroadcastMessage;
@@ -35,6 +34,7 @@
import android.telephony.SmsCbMessage;
import android.util.Log;
+import java.util.ArrayList;
import java.util.HashSet;
/**
@@ -46,25 +46,12 @@
public class CellBroadcastAlertService extends Service {
private static final String TAG = "CellBroadcastAlertService";
- /** Identifier for notification ID extra. */
- public static final String SMS_CB_NOTIFICATION_ID_EXTRA =
- "com.android.cellbroadcastreceiver.SMS_CB_NOTIFICATION_ID";
-
- /** Intent extra to indicate a previously unread alert. */
- static final String NEW_ALERT_EXTRA = "com.android.cellbroadcastreceiver.NEW_ALERT";
-
/** Intent action to display alert dialog/notification, after verifying the alert is new. */
static final String SHOW_NEW_ALERT_ACTION = "cellbroadcastreceiver.SHOW_NEW_ALERT";
/** Use the same notification ID for non-emergency alerts. */
static final int NOTIFICATION_ID = 1;
- /** CPU wake lock while handling emergency alert notification. */
- private PowerManager.WakeLock mWakeLock;
-
- /** Hold the wake lock for 5 seconds, which should be enough time to display the alert. */
- private static final int WAKE_LOCK_TIMEOUT = 5000;
-
/** Container for message ID and geographical scope, for duplicate message detection. */
private static final class MessageIdAndScope {
private final int mMessageId;
@@ -178,8 +165,7 @@
return;
}
- if (cbm.isEmergencyAlertMessage() || CellBroadcastConfigService
- .isOperatorDefinedEmergencyId(cbm.getServiceCategory())) {
+ if (CellBroadcastConfigService.isEmergencyAlertMessage(cbm)) {
// start alert sound / vibration / TTS and display full-screen alert
openEmergencyAlertNotification(cbm);
} else {
@@ -233,25 +219,13 @@
return true; // other broadcast messages are always enabled
}
- private void acquireTimedWakelock(int timeout) {
- if (mWakeLock == null) {
- PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
- // Note: acquiring a PARTIAL_WAKE_LOCK and setting window flag FLAG_TURN_SCREEN_ON in
- // CellBroadcastAlertFullScreen is not sufficient to turn on the screen by itself.
- // Use SCREEN_BRIGHT_WAKE_LOCK here as a workaround to ensure the screen turns on.
- mWakeLock = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK
- | PowerManager.ACQUIRE_CAUSES_WAKEUP, TAG);
- }
- mWakeLock.acquire(timeout);
- }
-
/**
* Display a full-screen alert message for emergency alerts.
* @param message the alert to display
*/
private void openEmergencyAlertNotification(CellBroadcastMessage message) {
// Acquire a CPU wake lock until the alert dialog and audio start playing.
- acquireTimedWakelock(WAKE_LOCK_TIMEOUT);
+ CellBroadcastAlertWakeLock.acquireScreenCpuWakeLock(this);
// Close dialogs and window shade
Intent closeDialogs = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
@@ -283,8 +257,6 @@
prefs.getBoolean(CellBroadcastSettings.KEY_ENABLE_ALERT_VIBRATE, true));
}
- int channelTitleId = CellBroadcastResources.getDialogTitleResource(message);
- CharSequence channelName = getText(channelTitleId);
String messageBody = message.getMessageBody();
if (prefs.getBoolean(CellBroadcastSettings.KEY_ENABLE_ALERT_SPEECH, true)) {
@@ -303,9 +275,6 @@
}
startService(audioIntent);
- // Use lower 32 bits of emergency alert delivery time for notification ID
- int notificationId = (int) message.getDeliveryTime();
-
// Decide which activity to start based on the state of the keyguard.
Class c = CellBroadcastAlertDialog.class;
KeyguardManager km = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
@@ -314,23 +283,12 @@
c = CellBroadcastAlertFullScreen.class;
}
- Intent notify = createDisplayMessageIntent(this, c, message, notificationId);
- PendingIntent pi = PendingIntent.getActivity(this, notificationId, notify, 0);
+ ArrayList<CellBroadcastMessage> messageList = new ArrayList<CellBroadcastMessage>(1);
+ messageList.add(message);
- Notification.Builder builder = new Notification.Builder(this)
- .setSmallIcon(R.drawable.ic_notify_alert)
- .setTicker(getText(CellBroadcastResources.getDialogTitleResource(message)))
- .setWhen(System.currentTimeMillis())
- .setContentIntent(pi)
- .setFullScreenIntent(pi, true)
- .setContentTitle(channelName)
- .setContentText(messageBody)
- .setDefaults(Notification.DEFAULT_LIGHTS);
-
- NotificationManager notificationManager =
- (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
-
- notificationManager.notify(notificationId, builder.getNotification());
+ Intent alertDialogIntent = createDisplayMessageIntent(this, c, messageList);
+ alertDialogIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ startActivity(alertDialogIntent);
}
/**
@@ -343,11 +301,17 @@
CharSequence channelName = getText(channelTitleId);
String messageBody = message.getMessageBody();
- // Use the same ID to create a single notification for multiple non-emergency alerts.
- int notificationId = NOTIFICATION_ID;
+ // Pass the list of unread non-emergency CellBroadcastMessages
+ ArrayList<CellBroadcastMessage> messageList = CellBroadcastReceiverApp
+ .addNewMessageToList(message);
- PendingIntent pi = PendingIntent.getActivity(this, 0, createDisplayMessageIntent(
- this, CellBroadcastListActivity.class, message, notificationId), 0);
+ // Create intent to show the new messages when user selects the notification.
+ Intent intent = createDisplayMessageIntent(this, CellBroadcastAlertDialog.class,
+ messageList);
+ intent.putExtra(CellBroadcastAlertFullScreen.FROM_NOTIFICATION_EXTRA, true);
+
+ PendingIntent pi = PendingIntent.getActivity(this, 0, intent,
+ PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_UPDATE_CURRENT);
// use default sound/vibration/lights for non-emergency broadcasts
Notification.Builder builder = new Notification.Builder(this)
@@ -360,7 +324,7 @@
builder.setDefaults(Notification.DEFAULT_ALL);
// increment unread alert count (decremented when user dismisses alert dialog)
- int unreadCount = CellBroadcastReceiverApp.incrementUnreadAlertCount();
+ int unreadCount = messageList.size();
if (unreadCount > 1) {
// use generic count of unread broadcasts if more than one unread
builder.setContentTitle(getString(R.string.notification_multiple_title));
@@ -369,27 +333,17 @@
builder.setContentTitle(channelName).setContentText(messageBody);
}
- Log.i(TAG, "addToNotificationBar notificationId: " + notificationId);
-
NotificationManager notificationManager =
(NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
- notificationManager.notify(notificationId, builder.getNotification());
+ notificationManager.notify(NOTIFICATION_ID, builder.build());
}
static Intent createDisplayMessageIntent(Context context, Class intentClass,
- CellBroadcastMessage message, int notificationId) {
+ ArrayList<CellBroadcastMessage> messageList) {
// Trigger the list activity to fire up a dialog that shows the received messages
Intent intent = new Intent(context, intentClass);
- intent.putExtra(CellBroadcastMessage.SMS_CB_MESSAGE_EXTRA, message);
- intent.putExtra(SMS_CB_NOTIFICATION_ID_EXTRA, notificationId);
- intent.putExtra(NEW_ALERT_EXTRA, true);
-
- // This line is needed to make this intent compare differently than the other intents
- // created here for other messages. Without this line, the PendingIntent always gets the
- // intent of a previous message and notification.
- intent.setType(Integer.toString(notificationId));
-
+ intent.putParcelableArrayListExtra(CellBroadcastMessage.SMS_CB_MESSAGE_EXTRA, messageList);
return intent;
}
diff --git a/src/com/android/cellbroadcastreceiver/CellBroadcastAlertWakeLock.java b/src/com/android/cellbroadcastreceiver/CellBroadcastAlertWakeLock.java
new file mode 100644
index 0000000..a1360b8
--- /dev/null
+++ b/src/com/android/cellbroadcastreceiver/CellBroadcastAlertWakeLock.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2012 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 com.android.cellbroadcastreceiver;
+
+import android.content.Context;
+import android.os.PowerManager;
+import android.util.Log;
+
+/**
+ * Hold a wakelock that can be acquired in the CellBroadcastAlertService and
+ * released in the CellBroadcastAlertFullScreen Activity.
+ */
+class CellBroadcastAlertWakeLock {
+ private static final String TAG = "CellBroadcastAlertWakeLock";
+
+ private static PowerManager.WakeLock sCpuWakeLock;
+
+ private CellBroadcastAlertWakeLock() {}
+
+ static void acquireScreenCpuWakeLock(Context context) {
+ if (sCpuWakeLock != null) {
+ return;
+ }
+ PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
+ sCpuWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK
+ | PowerManager.ACQUIRE_CAUSES_WAKEUP | PowerManager.ON_AFTER_RELEASE, TAG);
+ sCpuWakeLock.acquire();
+ Log.d(TAG, "acquired screen + CPU wake lock");
+ }
+
+ static void releaseCpuLock() {
+ if (sCpuWakeLock != null) {
+ sCpuWakeLock.release();
+ sCpuWakeLock = null;
+ Log.d(TAG, "released screen + CPU wake lock");
+ }
+ }
+}
diff --git a/src/com/android/cellbroadcastreceiver/CellBroadcastConfigService.java b/src/com/android/cellbroadcastreceiver/CellBroadcastConfigService.java
index ad77dc2..dd99dc5 100644
--- a/src/com/android/cellbroadcastreceiver/CellBroadcastConfigService.java
+++ b/src/com/android/cellbroadcastreceiver/CellBroadcastConfigService.java
@@ -22,6 +22,7 @@
import android.content.res.Resources;
import android.os.SystemProperties;
import android.preference.PreferenceManager;
+import android.telephony.CellBroadcastMessage;
import android.telephony.SmsManager;
import android.text.TextUtils;
import android.util.Log;
@@ -80,13 +81,24 @@
}
}
- static boolean isOperatorDefinedEmergencyId(int messageId) {
+ /**
+ * Returns true if this is a standard or operator-defined emergency alert message.
+ * This includes all ETWS and CMAS alerts, except for AMBER alerts.
+ * @param message the message to test
+ * @return true if the message is an emergency alert; false otherwise
+ */
+ static boolean isEmergencyAlertMessage(CellBroadcastMessage message) {
+ if (message.isEmergencyAlertMessage()) {
+ return true;
+ }
+
// Check for system property defining the emergency channel ranges to enable
String emergencyIdRange = SystemProperties.get("ro.cellbroadcast.emergencyids");
if (TextUtils.isEmpty(emergencyIdRange)) {
return false;
}
try {
+ int messageId = message.getServiceCategory();
for (String channelRange : emergencyIdRange.split(",")) {
int dashIndex = channelRange.indexOf('-');
if (dashIndex != -1) {
diff --git a/src/com/android/cellbroadcastreceiver/CellBroadcastContentProvider.java b/src/com/android/cellbroadcastreceiver/CellBroadcastContentProvider.java
index f368725..7460f78 100644
--- a/src/com/android/cellbroadcastreceiver/CellBroadcastContentProvider.java
+++ b/src/com/android/cellbroadcastreceiver/CellBroadcastContentProvider.java
@@ -252,19 +252,15 @@
/**
* Internal method to delete a cell broadcast by row ID and notify observers.
* @param rowId the row ID of the broadcast to delete
- * @param decrementUnreadCount true to decrement the count of unread alerts
* @return true if the database was updated, false otherwise
*/
- boolean deleteBroadcast(long rowId, boolean decrementUnreadCount) {
+ boolean deleteBroadcast(long rowId) {
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
int rowCount = db.delete(CellBroadcastDatabaseHelper.TABLE_NAME,
Telephony.CellBroadcasts._ID + "=?",
new String[]{Long.toString(rowId)});
if (rowCount != 0) {
- if (decrementUnreadCount) {
- CellBroadcastReceiverApp.decrementUnreadAlertCount();
- }
return true;
} else {
Log.e(TAG, "failed to delete broadcast at row " + rowId);
@@ -281,7 +277,6 @@
int rowCount = db.delete(CellBroadcastDatabaseHelper.TABLE_NAME, null, null);
if (rowCount != 0) {
- CellBroadcastReceiverApp.resetUnreadAlertCount();
return true;
} else {
Log.e(TAG, "failed to delete all broadcasts");
diff --git a/src/com/android/cellbroadcastreceiver/CellBroadcastListActivity.java b/src/com/android/cellbroadcastreceiver/CellBroadcastListActivity.java
index 112cb92..777c24e 100644
--- a/src/com/android/cellbroadcastreceiver/CellBroadcastListActivity.java
+++ b/src/com/android/cellbroadcastreceiver/CellBroadcastListActivity.java
@@ -44,6 +44,8 @@
import android.widget.CursorAdapter;
import android.widget.ListView;
+import java.util.ArrayList;
+
/**
* This activity provides a list view of received cell broadcasts. Most of the work is handled
* in the inner CursorLoaderListFragment class.
@@ -159,7 +161,9 @@
private void showDialogAndMarkRead(CellBroadcastMessage cbm) {
// show emergency alerts with the warning icon, but don't play alert tone
Intent i = new Intent(getActivity(), CellBroadcastAlertDialog.class);
- i.putExtra(CellBroadcastMessage.SMS_CB_MESSAGE_EXTRA, cbm);
+ ArrayList<CellBroadcastMessage> messageList = new ArrayList<CellBroadcastMessage>(1);
+ messageList.add(cbm);
+ i.putParcelableArrayListExtra(CellBroadcastMessage.SMS_CB_MESSAGE_EXTRA, messageList);
startActivity(i);
}
@@ -190,11 +194,8 @@
if (cursor != null && cursor.getPosition() >= 0) {
switch (item.getItemId()) {
case MENU_DELETE:
- // We need to decrement the unread alert count if deleting unread alert
- boolean isUnread = (cursor.getInt(cursor.getColumnIndexOrThrow(
- Telephony.CellBroadcasts.MESSAGE_READ)) == 0);
confirmDeleteThread(cursor.getLong(cursor.getColumnIndexOrThrow(
- Telephony.CellBroadcasts._ID)), isUnread);
+ Telephony.CellBroadcasts._ID)));
break;
case MENU_VIEW_DETAILS:
@@ -212,7 +213,7 @@
public boolean onOptionsItemSelected(MenuItem item) {
switch(item.getItemId()) {
case MENU_DELETE_ALL:
- confirmDeleteThread(-1, false);
+ confirmDeleteThread(-1);
break;
case MENU_PREFERENCES:
@@ -229,10 +230,9 @@
/**
* Start the process of putting up a dialog to confirm deleting a broadcast.
* @param rowId the row ID of the broadcast to delete, or -1 to delete all broadcasts
- * @param unread true if the alert was not already marked as read
*/
- public void confirmDeleteThread(long rowId, boolean unread) {
- DeleteThreadListener listener = new DeleteThreadListener(rowId, unread);
+ public void confirmDeleteThread(long rowId) {
+ DeleteThreadListener listener = new DeleteThreadListener(rowId);
confirmDeleteThreadDialog(listener, (rowId == -1), getActivity());
}
@@ -258,11 +258,9 @@
public class DeleteThreadListener implements OnClickListener {
private final long mRowId;
- private final boolean mIsUnread;
- public DeleteThreadListener(long rowId, boolean unread) {
+ public DeleteThreadListener(long rowId) {
mRowId = rowId;
- mIsUnread = unread;
}
@Override
@@ -274,7 +272,7 @@
@Override
public boolean execute(CellBroadcastContentProvider provider) {
if (mRowId != -1) {
- return provider.deleteBroadcast(mRowId, mIsUnread);
+ return provider.deleteBroadcast(mRowId);
} else {
return provider.deleteAllBroadcasts();
}
@@ -285,29 +283,4 @@
}
}
}
-
- @Override
- protected void onNewIntent(Intent intent) {
- if (intent == null) {
- return;
- }
-
- Bundle extras = intent.getExtras();
- if (extras == null) {
- return;
- }
-
- CellBroadcastMessage cbm = extras.getParcelable(CellBroadcastMessage.SMS_CB_MESSAGE_EXTRA);
- int notificationId = extras.getInt(CellBroadcastAlertService.SMS_CB_NOTIFICATION_ID_EXTRA);
-
- // Dismiss the notification that brought us here.
- NotificationManager notificationManager =
- (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
- notificationManager.cancel(notificationId);
-
- // launch the dialog activity to show the alert
- Intent i = new Intent(this, CellBroadcastAlertDialog.class);
- i.putExtra(CellBroadcastMessage.SMS_CB_MESSAGE_EXTRA, cbm);
- startActivity(i);
- }
}
diff --git a/src/com/android/cellbroadcastreceiver/CellBroadcastOptOutActivity.java b/src/com/android/cellbroadcastreceiver/CellBroadcastOptOutActivity.java
new file mode 100644
index 0000000..76ed537
--- /dev/null
+++ b/src/com/android/cellbroadcastreceiver/CellBroadcastOptOutActivity.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2012 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 com.android.cellbroadcastreceiver;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.Log;
+
+/**
+ * Container activity for CMAS opt-in/opt-out alert dialog.
+ */
+public class CellBroadcastOptOutActivity extends Activity {
+ private static final String TAG = "CellBroadcastOptOutActivity";
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ Log.d(TAG, "created activity");
+ showOptOutDialog(this);
+ }
+
+ /**
+ * Show the opt-out dialog. Uses the CellBroadcastAlertDialog activity unless the device is
+ * in restricted keyguard mode, in which case we create a new CellBroadcastOptOutActivity
+ * so that the dialog appears underneath the lock screen. The user must unlock the device
+ * to configure the settings, so we don't want to show the opt-in dialog before then.
+ */
+ static void showOptOutDialog(final Activity activity) {
+ AlertDialog.Builder builder = new AlertDialog.Builder(activity);
+ builder.setMessage(R.string.cmas_opt_out_dialog_text)
+ .setPositiveButton(R.string.cmas_opt_out_button_yes,
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ Log.d(TAG, "User clicked Yes");
+ activity.finish();
+ }
+ })
+ .setNegativeButton(R.string.cmas_opt_out_button_no,
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ Log.d(TAG, "User clicked No");
+ Intent intent = new Intent(activity, CellBroadcastSettings.class);
+ activity.startActivity(intent);
+ activity.finish();
+ }
+ })
+ .create().show();
+ }
+}
diff --git a/src/com/android/cellbroadcastreceiver/CellBroadcastReceiverApp.java b/src/com/android/cellbroadcastreceiver/CellBroadcastReceiverApp.java
index eb21e17..65e8c72 100644
--- a/src/com/android/cellbroadcastreceiver/CellBroadcastReceiverApp.java
+++ b/src/com/android/cellbroadcastreceiver/CellBroadcastReceiverApp.java
@@ -17,9 +17,11 @@
package com.android.cellbroadcastreceiver;
import android.app.Application;
+import android.telephony.CellBroadcastMessage;
import android.util.Log;
import android.preference.PreferenceManager;
+import java.util.ArrayList;
import java.util.concurrent.atomic.AtomicInteger;
/**
@@ -36,29 +38,18 @@
PreferenceManager.setDefaultValues(this, R.xml.preferences, false);
}
- /** Number of unread non-emergency alerts since the device was booted. */
- private static AtomicInteger sUnreadAlertCount = new AtomicInteger();
+ /** List of unread non-emergency alerts to show when user selects the notification. */
+ private static final ArrayList<CellBroadcastMessage> sNewMessageList =
+ new ArrayList<CellBroadcastMessage>(4);
- /**
- * Increments the number of unread non-emergency alerts, returning the new value.
- * @return the updated number of unread non-emergency alerts, after incrementing
- */
- static int incrementUnreadAlertCount() {
- return sUnreadAlertCount.incrementAndGet();
+ /** Adds a new unread non-emergency message and returns the current list. */
+ static ArrayList<CellBroadcastMessage> addNewMessageToList(CellBroadcastMessage message) {
+ sNewMessageList.add(message);
+ return sNewMessageList;
}
- /**
- * Decrements the number of unread non-emergency alerts after the user reads it.
- */
- static void decrementUnreadAlertCount() {
- if (sUnreadAlertCount.decrementAndGet() < 0) {
- Log.e(TAG, "mUnreadAlertCount < 0, resetting to 0");
- sUnreadAlertCount.set(0);
- }
- }
-
- /** Resets the unread alert count to zero after user deletes all alerts. */
- static void resetUnreadAlertCount() {
- sUnreadAlertCount.set(0);
+ /** Clears the list of unread non-emergency messages. */
+ static void clearNewMessageList() {
+ sNewMessageList.clear();
}
}
diff --git a/src/com/android/cellbroadcastreceiver/CellBroadcastResources.java b/src/com/android/cellbroadcastreceiver/CellBroadcastResources.java
index fedd153..76d4b42 100644
--- a/src/com/android/cellbroadcastreceiver/CellBroadcastResources.java
+++ b/src/com/android/cellbroadcastreceiver/CellBroadcastResources.java
@@ -289,7 +289,7 @@
}
}
- if (cbm.isPublicAlertMessage()) {
+ if (CellBroadcastConfigService.isEmergencyAlertMessage(cbm)) {
return R.string.pws_other_message_identifiers;
} else {
return R.string.cb_other_message_identifiers;
diff --git a/src/com/android/cellbroadcastreceiver/CellBroadcastSettings.java b/src/com/android/cellbroadcastreceiver/CellBroadcastSettings.java
index 7e7915d..a7c7482 100644
--- a/src/com/android/cellbroadcastreceiver/CellBroadcastSettings.java
+++ b/src/com/android/cellbroadcastreceiver/CellBroadcastSettings.java
@@ -79,6 +79,9 @@
// Enabled by default for phones sold in Brazil, otherwise this setting may be hidden.
public static final String KEY_ENABLE_CHANNEL_50_ALERTS = "enable_channel_50_alerts";
+ // Preference key for initial opt-in/opt-out dialog.
+ public static final String KEY_SHOW_CMAS_OPT_OUT_DIALOG = "show_cmas_opt_out_dialog";
+
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
diff --git a/tests/res/layout/test_buttons.xml b/tests/res/layout/test_buttons.xml
index 2dd3849..96103cb 100644
--- a/tests/res/layout/test_buttons.xml
+++ b/tests/res/layout/test_buttons.xml
@@ -25,6 +25,23 @@
android:layout_height="match_parent"
android:orientation="vertical">
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="horizontal">
+
+ <TextView android:id="@+id/message_id_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/message_id_label" />
+
+ <EditText android:id="@+id/message_id"
+ android:layout_width="80dp"
+ android:layout_height="wrap_content"
+ android:inputType="number" />
+
+ </LinearLayout>
+
<CheckBox android:id="@+id/button_delay_broadcast"
android:text="@string/button_delay_broadcast"
android:layout_marginLeft="20dp"
diff --git a/tests/res/values/strings.xml b/tests/res/values/strings.xml
index 5968e1c..b1b1031 100644
--- a/tests/res/values/strings.xml
+++ b/tests/res/values/strings.xml
@@ -39,4 +39,5 @@
<string name="button_gsm_ucs2_with_language_type">Send GSM UCS-2 With Language</string>
<string name="button_gsm_ucs2_with_language_umts_type">Send UMTS UCS-2 With Language</string>
<string name="button_delay_broadcast">Delay 5 seconds before sending</string>
+ <string name="message_id_label">Message ID:</string>
</resources>
diff --git a/tests/src/com/android/cellbroadcastreceiver/tests/SendCdmaCmasMessages.java b/tests/src/com/android/cellbroadcastreceiver/tests/SendCdmaCmasMessages.java
index 17f76cb..71ca812 100644
--- a/tests/src/com/android/cellbroadcastreceiver/tests/SendCdmaCmasMessages.java
+++ b/tests/src/com/android/cellbroadcastreceiver/tests/SendCdmaCmasMessages.java
@@ -62,9 +62,9 @@
private static final String IS91_TEXT = "IS91 SHORT MSG"; // max length 14 chars
- public static void testSendCmasPresAlert(Activity activity) {
+ public static void testSendCmasPresAlert(Activity activity, int messageId) {
SmsCbMessage cbMessage = createCmasSmsMessage(
- SmsEnvelope.SERVICE_CATEGORY_CMAS_PRESIDENTIAL_LEVEL_ALERT, 12345, "en",
+ SmsEnvelope.SERVICE_CATEGORY_CMAS_PRESIDENTIAL_LEVEL_ALERT, messageId, "en",
PRES_ALERT, SmsCbCmasInfo.CMAS_CATEGORY_GEO,
SmsCbCmasInfo.CMAS_RESPONSE_TYPE_PREPARE, SmsCbCmasInfo.CMAS_SEVERITY_EXTREME,
SmsCbCmasInfo.CMAS_URGENCY_EXPECTED, SmsCbCmasInfo.CMAS_CERTAINTY_LIKELY);
@@ -74,9 +74,9 @@
activity.sendOrderedBroadcast(intent, "android.permission.RECEIVE_SMS");
}
- public static void testSendCmasExtremeAlert(Activity activity) {
+ public static void testSendCmasExtremeAlert(Activity activity, int messageId) {
SmsCbMessage cbMessage = createCmasSmsMessage(
- SmsEnvelope.SERVICE_CATEGORY_CMAS_EXTREME_THREAT, 23456, "en",
+ SmsEnvelope.SERVICE_CATEGORY_CMAS_EXTREME_THREAT, messageId, "en",
EXTREME_ALERT, SmsCbCmasInfo.CMAS_CATEGORY_MET,
SmsCbCmasInfo.CMAS_RESPONSE_TYPE_PREPARE, SmsCbCmasInfo.CMAS_SEVERITY_EXTREME,
SmsCbCmasInfo.CMAS_URGENCY_EXPECTED, SmsCbCmasInfo.CMAS_CERTAINTY_OBSERVED);
@@ -86,9 +86,9 @@
activity.sendOrderedBroadcast(intent, "android.permission.RECEIVE_SMS");
}
- public static void testSendCmasSevereAlert(Activity activity) {
+ public static void testSendCmasSevereAlert(Activity activity, int messageId) {
SmsCbMessage cbMessage = createCmasSmsMessage(
- SmsEnvelope.SERVICE_CATEGORY_CMAS_SEVERE_THREAT, 34567, "en",
+ SmsEnvelope.SERVICE_CATEGORY_CMAS_SEVERE_THREAT, messageId, "en",
SEVERE_ALERT, SmsCbCmasInfo.CMAS_CATEGORY_HEALTH,
SmsCbCmasInfo.CMAS_RESPONSE_TYPE_AVOID, SmsCbCmasInfo.CMAS_SEVERITY_SEVERE,
SmsCbCmasInfo.CMAS_URGENCY_IMMEDIATE, SmsCbCmasInfo.CMAS_CERTAINTY_LIKELY);
@@ -98,9 +98,9 @@
activity.sendOrderedBroadcast(intent, "android.permission.RECEIVE_SMS");
}
- public static void testSendCmasAmberAlert(Activity activity) {
+ public static void testSendCmasAmberAlert(Activity activity, int messageId) {
SmsCbMessage cbMessage = createCmasSmsMessage(
- SmsEnvelope.SERVICE_CATEGORY_CMAS_CHILD_ABDUCTION_EMERGENCY, 45678, "en",
+ SmsEnvelope.SERVICE_CATEGORY_CMAS_CHILD_ABDUCTION_EMERGENCY, messageId, "en",
AMBER_ALERT, SmsCbCmasInfo.CMAS_CATEGORY_UNKNOWN,
SmsCbCmasInfo.CMAS_RESPONSE_TYPE_UNKNOWN, SmsCbCmasInfo.CMAS_SEVERITY_UNKNOWN,
SmsCbCmasInfo.CMAS_URGENCY_UNKNOWN, SmsCbCmasInfo.CMAS_CERTAINTY_UNKNOWN);
@@ -110,9 +110,9 @@
activity.sendOrderedBroadcast(intent, "android.permission.RECEIVE_SMS");
}
- public static void testSendCmasMonthlyTest(Activity activity) {
+ public static void testSendCmasMonthlyTest(Activity activity, int messageId) {
SmsCbMessage cbMessage = createCmasSmsMessage(
- SmsEnvelope.SERVICE_CATEGORY_CMAS_TEST_MESSAGE, 56789, "en",
+ SmsEnvelope.SERVICE_CATEGORY_CMAS_TEST_MESSAGE, messageId, "en",
MONTHLY_TEST_ALERT, SmsCbCmasInfo.CMAS_CATEGORY_UNKNOWN,
SmsCbCmasInfo.CMAS_RESPONSE_TYPE_UNKNOWN, SmsCbCmasInfo.CMAS_SEVERITY_UNKNOWN,
SmsCbCmasInfo.CMAS_URGENCY_UNKNOWN, SmsCbCmasInfo.CMAS_CERTAINTY_UNKNOWN);
diff --git a/tests/src/com/android/cellbroadcastreceiver/tests/SendTestBroadcastActivity.java b/tests/src/com/android/cellbroadcastreceiver/tests/SendTestBroadcastActivity.java
index 0e73101..f47ffd2 100644
--- a/tests/src/com/android/cellbroadcastreceiver/tests/SendTestBroadcastActivity.java
+++ b/tests/src/com/android/cellbroadcastreceiver/tests/SendTestBroadcastActivity.java
@@ -20,16 +20,20 @@
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
+import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.CheckBox;
+import android.widget.EditText;
+
+import java.util.Random;
/**
* Activity to send test cell broadcast messages from GUI.
*/
public class SendTestBroadcastActivity extends Activity {
- private static String TAG = "SendTestBroadcastActivity";
+ private static final String TAG = "SendTestBroadcastActivity";
/** Whether to delay before sending test message. */
private boolean mDelayBeforeSending;
@@ -37,19 +41,35 @@
/** Delay time before sending test message (when box is checked). */
private static final int DELAY_BEFORE_SENDING_MSEC = 5000;
- /** Callback for sending test message after delay */
- private OnClickListener mPendingButtonClick;
-
- private Handler mDelayHandler = new Handler() {
+ private final Handler mDelayHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
// call the onClick() method again, passing null View.
// The callback will ignore mDelayBeforeSending when the View is null.
- mPendingButtonClick.onClick(null);
+ OnClickListener pendingButtonClick = (OnClickListener) msg.obj;
+ pendingButtonClick.onClick(null);
}
};
-
+ /**
+ * Increment the message ID field and return the previous value.
+ * @return the current value of the message ID text field
+ */
+ private int getMessageId() {
+ EditText messageIdField = (EditText) findViewById(R.id.message_id);
+ int messageId = 0;
+ try {
+ messageId = Integer.parseInt(messageIdField.getText().toString());
+ } catch (NumberFormatException ignored) {
+ Log.e(TAG, "Invalid message ID");
+ }
+ int newMessageId = (messageId + 1) % 65536;
+ if (newMessageId == 0) {
+ newMessageId = 1;
+ }
+ messageIdField.setText(String.valueOf(newMessageId));
+ return messageId;
+ }
/**
* Initialization of the Activity after it is first created. Must at least
@@ -61,14 +81,18 @@
super.onCreate(savedInstanceState);
setContentView(R.layout.test_buttons);
+
+ /* Set message ID to a random value from 1-65535. */
+ EditText messageIdField = (EditText) findViewById(R.id.message_id);
+ messageIdField.setText(String.valueOf(new Random().nextInt(65535) + 1));
/* Send an ETWS normal broadcast message to app. */
Button etwsNormalTypeButton = (Button) findViewById(R.id.button_etws_normal_type);
etwsNormalTypeButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
if (mDelayBeforeSending && v != null) {
- mPendingButtonClick = this;
- mDelayHandler.sendEmptyMessageDelayed(0, DELAY_BEFORE_SENDING_MSEC);
+ Message msg = mDelayHandler.obtainMessage(0, this);
+ mDelayHandler.sendMessageDelayed(msg, DELAY_BEFORE_SENDING_MSEC);
} else {
SendTestMessages.testSendEtwsMessageNormal(SendTestBroadcastActivity.this);
}
@@ -80,8 +104,8 @@
etwsCancelTypeButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
if (mDelayBeforeSending && v != null) {
- mPendingButtonClick = this;
- mDelayHandler.sendEmptyMessageDelayed(0, DELAY_BEFORE_SENDING_MSEC);
+ Message msg = mDelayHandler.obtainMessage(0, this);
+ mDelayHandler.sendMessageDelayed(msg, DELAY_BEFORE_SENDING_MSEC);
} else {
SendTestMessages.testSendEtwsMessageCancel(SendTestBroadcastActivity.this);
}
@@ -93,8 +117,8 @@
etwsTestTypeButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
if (mDelayBeforeSending && v != null) {
- mPendingButtonClick = this;
- mDelayHandler.sendEmptyMessageDelayed(0, DELAY_BEFORE_SENDING_MSEC);
+ Message msg = mDelayHandler.obtainMessage(0, this);
+ mDelayHandler.sendMessageDelayed(msg, DELAY_BEFORE_SENDING_MSEC);
} else {
SendTestMessages.testSendEtwsMessageTest(SendTestBroadcastActivity.this);
}
@@ -106,10 +130,11 @@
cmasPresAlertButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
if (mDelayBeforeSending && v != null) {
- mPendingButtonClick = this;
- mDelayHandler.sendEmptyMessageDelayed(0, DELAY_BEFORE_SENDING_MSEC);
+ Message msg = mDelayHandler.obtainMessage(0, this);
+ mDelayHandler.sendMessageDelayed(msg, DELAY_BEFORE_SENDING_MSEC);
} else {
- SendCdmaCmasMessages.testSendCmasPresAlert(SendTestBroadcastActivity.this);
+ SendCdmaCmasMessages.testSendCmasPresAlert(SendTestBroadcastActivity.this,
+ getMessageId());
}
}
});
@@ -119,10 +144,11 @@
cmasExtremeAlertButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
if (mDelayBeforeSending && v != null) {
- mPendingButtonClick = this;
- mDelayHandler.sendEmptyMessageDelayed(0, DELAY_BEFORE_SENDING_MSEC);
+ Message msg = mDelayHandler.obtainMessage(0, this);
+ mDelayHandler.sendMessageDelayed(msg, DELAY_BEFORE_SENDING_MSEC);
} else {
- SendCdmaCmasMessages.testSendCmasExtremeAlert(SendTestBroadcastActivity.this);
+ SendCdmaCmasMessages.testSendCmasExtremeAlert(SendTestBroadcastActivity.this,
+ getMessageId());
}
}
});
@@ -132,10 +158,11 @@
cmasSevereAlertButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
if (mDelayBeforeSending && v != null) {
- mPendingButtonClick = this;
- mDelayHandler.sendEmptyMessageDelayed(0, DELAY_BEFORE_SENDING_MSEC);
+ Message msg = mDelayHandler.obtainMessage(0, this);
+ mDelayHandler.sendMessageDelayed(msg, DELAY_BEFORE_SENDING_MSEC);
} else {
- SendCdmaCmasMessages.testSendCmasSevereAlert(SendTestBroadcastActivity.this);
+ SendCdmaCmasMessages.testSendCmasSevereAlert(SendTestBroadcastActivity.this,
+ getMessageId());
}
}
});
@@ -145,10 +172,11 @@
cmasAmberAlertButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
if (mDelayBeforeSending && v != null) {
- mPendingButtonClick = this;
- mDelayHandler.sendEmptyMessageDelayed(0, DELAY_BEFORE_SENDING_MSEC);
+ Message msg = mDelayHandler.obtainMessage(0, this);
+ mDelayHandler.sendMessageDelayed(msg, DELAY_BEFORE_SENDING_MSEC);
} else {
- SendCdmaCmasMessages.testSendCmasAmberAlert(SendTestBroadcastActivity.this);
+ SendCdmaCmasMessages.testSendCmasAmberAlert(SendTestBroadcastActivity.this,
+ getMessageId());
}
}
});
@@ -158,10 +186,11 @@
cmasMonthlyTestButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
if (mDelayBeforeSending && v != null) {
- mPendingButtonClick = this;
- mDelayHandler.sendEmptyMessageDelayed(0, DELAY_BEFORE_SENDING_MSEC);
+ Message msg = mDelayHandler.obtainMessage(0, this);
+ mDelayHandler.sendMessageDelayed(msg, DELAY_BEFORE_SENDING_MSEC);
} else {
- SendCdmaCmasMessages.testSendCmasMonthlyTest(SendTestBroadcastActivity.this);
+ SendCdmaCmasMessages.testSendCmasMonthlyTest(SendTestBroadcastActivity.this,
+ getMessageId());
}
}
});
@@ -171,8 +200,8 @@
gsm7bitTypeButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
if (mDelayBeforeSending && v != null) {
- mPendingButtonClick = this;
- mDelayHandler.sendEmptyMessageDelayed(0, DELAY_BEFORE_SENDING_MSEC);
+ Message msg = mDelayHandler.obtainMessage(0, this);
+ mDelayHandler.sendMessageDelayed(msg, DELAY_BEFORE_SENDING_MSEC);
} else {
SendTestMessages.testSendMessage7bit(SendTestBroadcastActivity.this);
}
@@ -184,8 +213,8 @@
gsm7bitUmtsTypeButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
if (mDelayBeforeSending && v != null) {
- mPendingButtonClick = this;
- mDelayHandler.sendEmptyMessageDelayed(0, DELAY_BEFORE_SENDING_MSEC);
+ Message msg = mDelayHandler.obtainMessage(0, this);
+ mDelayHandler.sendMessageDelayed(msg, DELAY_BEFORE_SENDING_MSEC);
} else {
SendTestMessages.testSendMessage7bitUmts(SendTestBroadcastActivity.this);
}
@@ -197,8 +226,8 @@
gsm7bitNoPaddingButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
if (mDelayBeforeSending && v != null) {
- mPendingButtonClick = this;
- mDelayHandler.sendEmptyMessageDelayed(0, DELAY_BEFORE_SENDING_MSEC);
+ Message msg = mDelayHandler.obtainMessage(0, this);
+ mDelayHandler.sendMessageDelayed(msg, DELAY_BEFORE_SENDING_MSEC);
} else {
SendTestMessages.testSendMessage7bitNoPadding(SendTestBroadcastActivity.this);
}
@@ -211,8 +240,8 @@
gsm7bitNoPaddingUmtsTypeButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
if (mDelayBeforeSending && v != null) {
- mPendingButtonClick = this;
- mDelayHandler.sendEmptyMessageDelayed(0, DELAY_BEFORE_SENDING_MSEC);
+ Message msg = mDelayHandler.obtainMessage(0, this);
+ mDelayHandler.sendMessageDelayed(msg, DELAY_BEFORE_SENDING_MSEC);
} else {
SendTestMessages.testSendMessage7bitNoPaddingUmts(SendTestBroadcastActivity.this);
}
@@ -225,8 +254,8 @@
gsm7bitMultipageButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
if (mDelayBeforeSending && v != null) {
- mPendingButtonClick = this;
- mDelayHandler.sendEmptyMessageDelayed(0, DELAY_BEFORE_SENDING_MSEC);
+ Message msg = mDelayHandler.obtainMessage(0, this);
+ mDelayHandler.sendMessageDelayed(msg, DELAY_BEFORE_SENDING_MSEC);
} else {
SendTestMessages.testSendMessage7bitMultipageGsm(SendTestBroadcastActivity.this);
}
@@ -239,8 +268,8 @@
gsm7bitMultipageUmtsButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
if (mDelayBeforeSending && v != null) {
- mPendingButtonClick = this;
- mDelayHandler.sendEmptyMessageDelayed(0, DELAY_BEFORE_SENDING_MSEC);
+ Message msg = mDelayHandler.obtainMessage(0, this);
+ mDelayHandler.sendMessageDelayed(msg, DELAY_BEFORE_SENDING_MSEC);
} else {
SendTestMessages.testSendMessage7bitMultipageUmts(SendTestBroadcastActivity.this);
}
@@ -253,8 +282,8 @@
gsm7bitWithLanguageButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
if (mDelayBeforeSending && v != null) {
- mPendingButtonClick = this;
- mDelayHandler.sendEmptyMessageDelayed(0, DELAY_BEFORE_SENDING_MSEC);
+ Message msg = mDelayHandler.obtainMessage(0, this);
+ mDelayHandler.sendMessageDelayed(msg, DELAY_BEFORE_SENDING_MSEC);
} else {
SendTestMessages.testSendMessage7bitWithLanguage(SendTestBroadcastActivity.this);
}
@@ -267,8 +296,8 @@
gsm7bitWithLanguageInBodyButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
if (mDelayBeforeSending && v != null) {
- mPendingButtonClick = this;
- mDelayHandler.sendEmptyMessageDelayed(0, DELAY_BEFORE_SENDING_MSEC);
+ Message msg = mDelayHandler.obtainMessage(0, this);
+ mDelayHandler.sendMessageDelayed(msg, DELAY_BEFORE_SENDING_MSEC);
} else {
SendTestMessages.testSendMessage7bitWithLanguageInBody(
SendTestBroadcastActivity.this);
@@ -282,8 +311,8 @@
gsm7bitWithLanguageUmtsButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
if (mDelayBeforeSending && v != null) {
- mPendingButtonClick = this;
- mDelayHandler.sendEmptyMessageDelayed(0, DELAY_BEFORE_SENDING_MSEC);
+ Message msg = mDelayHandler.obtainMessage(0, this);
+ mDelayHandler.sendMessageDelayed(msg, DELAY_BEFORE_SENDING_MSEC);
} else {
SendTestMessages.testSendMessage7bitWithLanguageInBodyUmts(SendTestBroadcastActivity.this);
}
@@ -295,8 +324,8 @@
gsmUcs2TypeButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
if (mDelayBeforeSending && v != null) {
- mPendingButtonClick = this;
- mDelayHandler.sendEmptyMessageDelayed(0, DELAY_BEFORE_SENDING_MSEC);
+ Message msg = mDelayHandler.obtainMessage(0, this);
+ mDelayHandler.sendMessageDelayed(msg, DELAY_BEFORE_SENDING_MSEC);
} else {
SendTestMessages.testSendMessageUcs2(SendTestBroadcastActivity.this);
}
@@ -308,8 +337,8 @@
gsmUcs2UmtsTypeButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
if (mDelayBeforeSending && v != null) {
- mPendingButtonClick = this;
- mDelayHandler.sendEmptyMessageDelayed(0, DELAY_BEFORE_SENDING_MSEC);
+ Message msg = mDelayHandler.obtainMessage(0, this);
+ mDelayHandler.sendMessageDelayed(msg, DELAY_BEFORE_SENDING_MSEC);
} else {
SendTestMessages.testSendMessageUcs2Umts(SendTestBroadcastActivity.this);
}
@@ -322,8 +351,8 @@
gsmUcs2MultipageUmtsTypeButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
if (mDelayBeforeSending && v != null) {
- mPendingButtonClick = this;
- mDelayHandler.sendEmptyMessageDelayed(0, DELAY_BEFORE_SENDING_MSEC);
+ Message msg = mDelayHandler.obtainMessage(0, this);
+ mDelayHandler.sendMessageDelayed(msg, DELAY_BEFORE_SENDING_MSEC);
} else {
SendTestMessages.testSendMessageUcs2MultipageUmts(SendTestBroadcastActivity.this);
}
@@ -336,8 +365,8 @@
gsmUcs2WithLanguageTypeButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
if (mDelayBeforeSending && v != null) {
- mPendingButtonClick = this;
- mDelayHandler.sendEmptyMessageDelayed(0, DELAY_BEFORE_SENDING_MSEC);
+ Message msg = mDelayHandler.obtainMessage(0, this);
+ mDelayHandler.sendMessageDelayed(msg, DELAY_BEFORE_SENDING_MSEC);
} else {
SendTestMessages.testSendMessageUcs2WithLanguageInBody(SendTestBroadcastActivity.this);
}
@@ -350,8 +379,8 @@
gsmUcs2WithLanguageUmtsTypeButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
if (mDelayBeforeSending && v != null) {
- mPendingButtonClick = this;
- mDelayHandler.sendEmptyMessageDelayed(0, DELAY_BEFORE_SENDING_MSEC);
+ Message msg = mDelayHandler.obtainMessage(0, this);
+ mDelayHandler.sendMessageDelayed(msg, DELAY_BEFORE_SENDING_MSEC);
} else {
SendTestMessages.testSendMessageUcs2WithLanguageUmts(SendTestBroadcastActivity.this);
}