summaryrefslogtreecommitdiffstats
path: root/src/com/android/cellbroadcastreceiver
diff options
context:
space:
mode:
authorJake Hamby <jhamby@google.com>2012-10-08 19:41:30 -0700
committerJake Hamby <jhamby@google.com>2012-10-12 14:47:59 -0700
commit57273ebfa13f96bf5aba9902b70e2b179fec9e4c (patch)
tree1355d9061b21f2f81a2c87a6eea51801be497c8d /src/com/android/cellbroadcastreceiver
parentd2869a10f34780efe8eecfe2719faaa91494a1b3 (diff)
downloadandroid_packages_apps_CellBroadcastReceiver-57273ebfa13f96bf5aba9902b70e2b179fec9e4c.tar.gz
android_packages_apps_CellBroadcastReceiver-57273ebfa13f96bf5aba9902b70e2b179fec9e4c.tar.bz2
android_packages_apps_CellBroadcastReceiver-57273ebfa13f96bf5aba9902b70e2b179fec9e4c.zip
Multiple fixes to CMAS app.
* Allow screen to turn off after 30 seconds for emergency alerts. * When multiple alerts are received, show them in reverse order. * After showing the first CMAS alert received on device (other than Presidential Alert), show opt-out dialog to allow user to opt-in or out of the various levels of CMAS alert. * Start/stop animating warning icon in activity pause/resume. * When multiple non-emergency alerts are received, show them all (most recent displayed first) when user selects the notification. * For emergency alerts, start the dialog activity directly instead of creating a PendingIntent and full screen notification. * Correctly save/restore the list of alerts in the alert dialog in onSaveInstanceState() when recreated after screen rotation. * Fix test app to increment the message ID and to send the correct alerts when multiple alerts are selected with 5 second delay. Bug: 6993660 Bug: 7041847 Bug: 7045506 Change-Id: Ic3ec08f0ebd693244891a4bf3a29479b832c2a3e
Diffstat (limited to 'src/com/android/cellbroadcastreceiver')
-rw-r--r--src/com/android/cellbroadcastreceiver/CellBroadcastAlertAudio.java13
-rw-r--r--src/com/android/cellbroadcastreceiver/CellBroadcastAlertDialog.java6
-rw-r--r--src/com/android/cellbroadcastreceiver/CellBroadcastAlertFullScreen.java403
-rw-r--r--src/com/android/cellbroadcastreceiver/CellBroadcastAlertService.java90
-rw-r--r--src/com/android/cellbroadcastreceiver/CellBroadcastAlertWakeLock.java52
-rw-r--r--src/com/android/cellbroadcastreceiver/CellBroadcastConfigService.java14
-rw-r--r--src/com/android/cellbroadcastreceiver/CellBroadcastContentProvider.java7
-rw-r--r--src/com/android/cellbroadcastreceiver/CellBroadcastListActivity.java49
-rw-r--r--src/com/android/cellbroadcastreceiver/CellBroadcastOptOutActivity.java68
-rw-r--r--src/com/android/cellbroadcastreceiver/CellBroadcastReceiverApp.java33
-rw-r--r--src/com/android/cellbroadcastreceiver/CellBroadcastResources.java2
-rw-r--r--src/com/android/cellbroadcastreceiver/CellBroadcastSettings.java3
12 files changed, 515 insertions, 225 deletions
diff --git a/src/com/android/cellbroadcastreceiver/CellBroadcastAlertAudio.java b/src/com/android/cellbroadcastreceiver/CellBroadcastAlertAudio.java
index 2b9dabc0..bc44ed1d 100644
--- a/src/com/android/cellbroadcastreceiver/CellBroadcastAlertAudio.java
+++ b/src/com/android/cellbroadcastreceiver/CellBroadcastAlertAudio.java
@@ -27,7 +27,6 @@ import android.media.MediaPlayer.OnErrorListener;
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 @@ public class CellBroadcastAlertAudio extends Service implements TextToSpeech.OnI
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 @@ public class CellBroadcastAlertAudio extends Service implements TextToSpeech.OnI
@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 @@ public class CellBroadcastAlertAudio extends Service implements TextToSpeech.OnI
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 3be8439d..f2509284 100644
--- a/src/com/android/cellbroadcastreceiver/CellBroadcastAlertDialog.java
+++ b/src/com/android/cellbroadcastreceiver/CellBroadcastAlertDialog.java
@@ -45,7 +45,7 @@ public class CellBroadcastAlertDialog extends CellBroadcastAlertFullScreen {
// 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 @@ public class CellBroadcastAlertDialog extends CellBroadcastAlertFullScreen {
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 99404265..cf6d7e5a 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.Button;
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";
+
+ /** Intent extra for non-emergency alerts sent when user selects the notification. */
+ static final String FROM_NOTIFICATION_EXTRA = "from_notification";
- /** Whether to show the flashing warning icon. */
- private boolean mIsEmergencyAlert;
+ /** List of cell broadcast messages to display (oldest to newest). */
+ ArrayList<CellBroadcastMessage> mMessageList;
- /** The cell broadcast message to display. */
- CellBroadcastMessage mMessage;
+ /** 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 @@ public class CellBroadcastAlertFullScreen extends Activity {
/** 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;
+
+ /** Animation handler for the flashing warning icon (emergency alerts only). */
+ private final AnimationHandler mAnimationHandler = new AnimationHandler();
+
+ /** Handler to add and remove screen on flags for emergency alerts. */
+ private final ScreenOffHandler mScreenOffHandler = new ScreenOffHandler();
+
+ /**
+ * 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();
+
+ /** Warning icon state: visible == true, hidden == false. */
+ private boolean mWarningIconVisible;
- /** Stop animating icon after {@link #onStop()} is called. */
- private boolean mStopAnimation;
+ /** The warning icon Drawable. */
+ private Drawable mWarningIcon;
- /** The warning icon Drawable. */
- private Drawable mWarningIcon;
+ /** The View containing the warning icon. */
+ private ImageView mWarningIconView;
- /** 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
+ }
+ 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);
+ }
- /** 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);
+ 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;
}
- } else {
- mWarningIconView.setImageAlpha(0);
- if (!mStopAnimation) {
- mAnimationHandler.sendEmptyMessageDelayed(0, WARNING_ICON_OFF_DURATION_MSEC);
+ }
+ 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;
}
}
- mIconAnimationState = !mIconAnimationState;
- mWarningIconView.invalidateDrawable(mWarningIcon);
+ 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 @@ public class CellBroadcastAlertFullScreen extends Activity {
| 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);
+ // Initialize the view.
+ LayoutInflater inflater = LayoutInflater.from(this);
+ setContentView(inflater.inflate(getLayoutResId(), null));
+
+ findViewById(R.id.dismissButton).setOnClickListener(
+ new Button.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ dismiss();
+ }
+ });
+
+ // 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 we were started from a notification, dismiss it.
+ clearNotification(intent);
}
- // Save message for passing from dialog to fullscreen activity, and for marking read.
- mMessage = getIntent().getParcelableExtra(
+ 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");
+ }
+ }
- updateLayout(mMessage);
+ /** 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;
}
- private void updateLayout(CellBroadcastMessage message) {
- LayoutInflater inflater = LayoutInflater.from(this);
-
- setContentView(inflater.inflate(getLayoutResId(), null));
-
- /* Initialize dialog text from alert message. */
+ /** 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());
-
- /* dismiss button: close notification */
- findViewById(R.id.dismissButton).setOnClickListener(
- new Button.OnClickListener() {
- public void onClick(View v) {
- dismiss();
- }
- });
-
- mIsEmergencyAlert = message.isPublicAlertMessage() || CellBroadcastConfigService
- .isOperatorDefinedEmergencyId(message.getServiceCategory());
-
- 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());
- }
}
/**
* 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 @@ public class CellBroadcastAlertFullScreen extends Activity {
// 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 @@ public class CellBroadcastAlertFullScreen extends Activity {
}
});
- 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 04fea0ff..07e1bfbb 100644
--- a/src/com/android/cellbroadcastreceiver/CellBroadcastAlertService.java
+++ b/src/com/android/cellbroadcastreceiver/CellBroadcastAlertService.java
@@ -26,7 +26,6 @@ import android.content.Intent;
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.SmsCbLocation;
import android.telephony.SmsCbMessage;
import android.util.Log;
+import java.util.ArrayList;
import java.util.HashSet;
/**
@@ -46,25 +46,12 @@ import java.util.HashSet;
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 @@ public class CellBroadcastAlertService extends Service {
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 @@ public class CellBroadcastAlertService extends Service {
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 @@ public class CellBroadcastAlertService extends Service {
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 @@ public class CellBroadcastAlertService extends Service {
}
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 @@ public class CellBroadcastAlertService extends Service {
c = CellBroadcastAlertFullScreen.class;
}
- Intent notify = createDisplayMessageIntent(this, c, message, notificationId);
- PendingIntent pi = PendingIntent.getActivity(this, notificationId, notify, 0);
-
- 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);
+ ArrayList<CellBroadcastMessage> messageList = new ArrayList<CellBroadcastMessage>(1);
+ messageList.add(message);
- 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 @@ public class CellBroadcastAlertService extends Service {
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);
+
+ // 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, createDisplayMessageIntent(
- this, CellBroadcastListActivity.class, message, notificationId), 0);
+ 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 @@ public class CellBroadcastAlertService extends Service {
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 @@ public class CellBroadcastAlertService extends Service {
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 00000000..a1360b8d
--- /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 ad77dc25..dd99dc56 100644
--- a/src/com/android/cellbroadcastreceiver/CellBroadcastConfigService.java
+++ b/src/com/android/cellbroadcastreceiver/CellBroadcastConfigService.java
@@ -22,6 +22,7 @@ import android.content.SharedPreferences;
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 @@ public class CellBroadcastConfigService extends IntentService {
}
}
- 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 f3687254..7460f784 100644
--- a/src/com/android/cellbroadcastreceiver/CellBroadcastContentProvider.java
+++ b/src/com/android/cellbroadcastreceiver/CellBroadcastContentProvider.java
@@ -252,19 +252,15 @@ public class CellBroadcastContentProvider extends ContentProvider {
/**
* 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 @@ public class CellBroadcastContentProvider extends ContentProvider {
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 112cb92a..777c24ef 100644
--- a/src/com/android/cellbroadcastreceiver/CellBroadcastListActivity.java
+++ b/src/com/android/cellbroadcastreceiver/CellBroadcastListActivity.java
@@ -44,6 +44,8 @@ import android.view.ViewGroup;
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 @@ public class CellBroadcastListActivity extends Activity {
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 @@ public class CellBroadcastListActivity extends Activity {
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 class CellBroadcastListActivity extends Activity {
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 @@ public class CellBroadcastListActivity extends Activity {
/**
* 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 CellBroadcastListActivity extends Activity {
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 @@ public class CellBroadcastListActivity extends Activity {
@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 @@ public class CellBroadcastListActivity extends Activity {
}
}
}
-
- @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 00000000..76ed5375
--- /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 eb21e17e..65e8c72b 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 @@ public class CellBroadcastReceiverApp extends Application {
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 fedd1533..76d4b42b 100644
--- a/src/com/android/cellbroadcastreceiver/CellBroadcastResources.java
+++ b/src/com/android/cellbroadcastreceiver/CellBroadcastResources.java
@@ -289,7 +289,7 @@ public class CellBroadcastResources {
}
}
- 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 7e7915da..a7c74824 100644
--- a/src/com/android/cellbroadcastreceiver/CellBroadcastSettings.java
+++ b/src/com/android/cellbroadcastreceiver/CellBroadcastSettings.java
@@ -79,6 +79,9 @@ public class CellBroadcastSettings extends PreferenceActivity {
// 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);