/*
* Copyright (C) 2014 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.example.android.support.wearable.notifications;
import android.app.Activity;
import android.app.Notification;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v4.app.NotificationManagerCompat;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.EditText;
import android.widget.Spinner;
import android.widget.TextView;
import java.util.Arrays;
/**
* Main activity which posts a notification when resumed, and allows customization
* of that notification via controls.
*/
public class MainActivity extends Activity implements Handler.Callback {
private static final int MSG_POST_NOTIFICATIONS = 0;
private static final long POST_NOTIFICATIONS_DELAY_MS = 200;
private Handler mHandler;
private Spinner mPresetSpinner;
private EditText mTitleEditText;
private EditText mTextEditText;
private TextWatcher mTextChangedListener;
private Spinner mPrioritySpinner;
private Spinner mActionsSpinner;
private CheckBox mIncludeLargeIconCheckbox;
private CheckBox mLocalOnlyCheckbox;
private CheckBox mIncludeContentIntentCheckbox;
private CheckBox mVibrateCheckbox;
private BackgroundPickers mBackgroundPickers;
private int postedNotificationCount = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mHandler = new Handler(this);
mTextChangedListener = new UpdateNotificationsOnTextChangeListener();
initPresetSpinner();
initTitleEditText();
initTextEditText();
initPrioritySpinner();
initActionsSpinner();
initIncludeLargeIconCheckbox();
initLocalOnlyCheckbox();
initIncludeContentIntentCheckbox();
initVibrateCheckbox();
initBackgroundPickers();
NotificationPreset preset = NotificationPresets.PRESETS[
mPresetSpinner.getSelectedItemPosition()];
updateTextEditors(preset);
}
@Override
protected void onResume() {
super.onResume();
updateNotifications(false /* cancelExisting */);
}
private void initPresetSpinner() {
mPresetSpinner = (Spinner) findViewById(R.id.preset_spinner);
mPresetSpinner.setAdapter(new NamedPresetSpinnerArrayAdapter(this,
NotificationPresets.PRESETS));
mPresetSpinner.post(new Runnable() {
@Override
public void run() {
mPresetSpinner.setOnItemSelectedListener(new PresetSpinnerListener());
}
});
}
private void initTitleEditText() {
mTitleEditText = (EditText) findViewById(R.id.title_editor);
}
private void initTextEditText() {
mTextEditText = (EditText) findViewById(R.id.text_editor);
}
private void initPrioritySpinner() {
mPrioritySpinner = (Spinner) findViewById(R.id.priority_spinner);
mPrioritySpinner.setAdapter(new NamedPresetSpinnerArrayAdapter(this,
PriorityPresets.PRESETS));
mPrioritySpinner.setSelection(Arrays.asList(PriorityPresets.PRESETS)
.indexOf(PriorityPresets.DEFAULT));
mPrioritySpinner.post(new Runnable() {
@Override
public void run() {
mPrioritySpinner.setOnItemSelectedListener(
new UpdateNotificationsOnItemSelectedListener(true /* cancelExisting */));
}
});
}
private void initActionsSpinner() {
mActionsSpinner = (Spinner) findViewById(R.id.actions_spinner);
mActionsSpinner.setAdapter(new NamedPresetSpinnerArrayAdapter(this,
ActionsPresets.PRESETS));
mActionsSpinner.post(new Runnable() {
@Override
public void run() {
mActionsSpinner.setOnItemSelectedListener(
new UpdateNotificationsOnItemSelectedListener(false /* cancelExisting */));
}
});
}
private void initIncludeLargeIconCheckbox() {
mIncludeLargeIconCheckbox = (CheckBox) findViewById(R.id.include_large_icon_checkbox);
mIncludeLargeIconCheckbox.setOnCheckedChangeListener(
new UpdateNotificationsOnCheckedChangeListener(false /* cancelExisting */));
}
private void initLocalOnlyCheckbox() {
mLocalOnlyCheckbox = (CheckBox) findViewById(R.id.local_only_checkbox);
mLocalOnlyCheckbox.setOnCheckedChangeListener(
new UpdateNotificationsOnCheckedChangeListener(false /* cancelExisting */));
}
private void initIncludeContentIntentCheckbox() {
mIncludeContentIntentCheckbox = (CheckBox) findViewById(
R.id.include_content_intent_checkbox);
mIncludeContentIntentCheckbox.setOnCheckedChangeListener(
new UpdateNotificationsOnCheckedChangeListener(false /* cancelExisting */));
}
private void initVibrateCheckbox() {
mVibrateCheckbox = (CheckBox) findViewById(R.id.vibrate_checkbox);
mVibrateCheckbox.setOnCheckedChangeListener(
new UpdateNotificationsOnCheckedChangeListener(false /* cancelExisting */));
}
private void initBackgroundPickers() {
mBackgroundPickers = new BackgroundPickers(
(ViewGroup) findViewById(R.id.background_pickers),
new BackgroundPickerListener());
}
private void updateTextEditors(NotificationPreset preset) {
mTitleEditText.setText(getString(preset.titleResId));
mTextEditText.setText(getString(preset.textResId));
if (preset == NotificationPresets.BASIC) {
findViewById(R.id.title_edit_field).setVisibility(View.VISIBLE);
mTitleEditText.addTextChangedListener(mTextChangedListener);
findViewById(R.id.text_edit_field).setVisibility(View.VISIBLE);
mTextEditText.addTextChangedListener(mTextChangedListener);
} else {
findViewById(R.id.title_edit_field).setVisibility(View.GONE);
mTitleEditText.removeTextChangedListener(mTextChangedListener);
findViewById(R.id.text_edit_field).setVisibility(View.GONE);
mTextEditText.removeTextChangedListener(mTextChangedListener);
}
}
/**
* Begin to re-post the sample notification(s).
*/
private void updateNotifications(boolean cancelExisting) {
// Disable messages to skip notification deleted messages during cancel.
sendBroadcast(new Intent(NotificationIntentReceiver.ACTION_DISABLE_MESSAGES)
.setClass(this, NotificationIntentReceiver.class));
if (cancelExisting) {
// Cancel all existing notifications to trigger fresh-posting behavior: For example,
// switching from HIGH to LOW priority does not cause a reordering in Notification Shade.
NotificationManagerCompat.from(this).cancelAll();
postedNotificationCount = 0;
// Post the updated notifications on a delay to avoid a cancel+post race condition
// with notification manager.
mHandler.removeMessages(MSG_POST_NOTIFICATIONS);
mHandler.sendEmptyMessageDelayed(MSG_POST_NOTIFICATIONS, POST_NOTIFICATIONS_DELAY_MS);
} else {
postNotifications();
}
}
/**
* Post the sample notification(s) using current options.
*/
private void postNotifications() {
sendBroadcast(new Intent(NotificationIntentReceiver.ACTION_ENABLE_MESSAGES)
.setClass(this, NotificationIntentReceiver.class));
NotificationPreset preset = NotificationPresets.PRESETS[
mPresetSpinner.getSelectedItemPosition()];
CharSequence titlePreset = mTitleEditText.getText();
CharSequence textPreset = mTextEditText.getText();
PriorityPreset priorityPreset = PriorityPresets.PRESETS[
mPrioritySpinner.getSelectedItemPosition()];
ActionsPreset actionsPreset = ActionsPresets.PRESETS[
mActionsSpinner.getSelectedItemPosition()];
if (preset.actionsRequired() && actionsPreset == ActionsPresets.NO_ACTIONS_PRESET) {
// If actions are required, but the no-actions preset was selected, change presets.
actionsPreset = ActionsPresets.SINGLE_ACTION_PRESET;
mActionsSpinner.setSelection(Arrays.asList(ActionsPresets.PRESETS).indexOf(
actionsPreset), true);
}
NotificationPreset.BuildOptions options = new NotificationPreset.BuildOptions(
titlePreset,
textPreset,
priorityPreset,
actionsPreset,
mIncludeLargeIconCheckbox.isChecked(),
mLocalOnlyCheckbox.isChecked(),
mIncludeContentIntentCheckbox.isChecked(),
mVibrateCheckbox.isChecked(),
mBackgroundPickers.getRes());
Notification[] notifications = preset.buildNotifications(this, options);
// Post new notifications
for (int i = 0; i < notifications.length; i++) {
NotificationManagerCompat.from(this).notify(i, notifications[i]);
}
// Cancel any that are beyond the current count.
for (int i = notifications.length; i < postedNotificationCount; i++) {
NotificationManagerCompat.from(this).cancel(i);
}
postedNotificationCount = notifications.length;
}
@Override
public boolean handleMessage(Message message) {
switch (message.what) {
case MSG_POST_NOTIFICATIONS:
postNotifications();
return true;
}
return false;
}
private class PresetSpinnerListener implements AdapterView.OnItemSelectedListener {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
NotificationPreset preset = NotificationPresets.PRESETS[position];
mBackgroundPickers.generatePickers(preset.countBackgroundPickersRequired());
updateTextEditors(preset);
updateNotifications(false /* cancelExisting */);
}
@Override
public void onNothingSelected(AdapterView<?> adapterView) {
}
}
private class UpdateNotificationsOnTextChangeListener implements TextWatcher {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void afterTextChanged(Editable s) {
updateNotifications(false /* cancelExisting */);
}
}
private class UpdateNotificationsOnItemSelectedListener
implements AdapterView.OnItemSelectedListener {
private final boolean mCancelExisting;
public UpdateNotificationsOnItemSelectedListener(boolean cancelExisting) {
mCancelExisting = cancelExisting;
}
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
updateNotifications(mCancelExisting);
}
@Override
public void onNothingSelected(AdapterView<?> adapterView) {
}
}
private class UpdateNotificationsOnCheckedChangeListener
implements CompoundButton.OnCheckedChangeListener {
private final boolean mCancelExisting;
public UpdateNotificationsOnCheckedChangeListener(boolean cancelExisting) {
mCancelExisting = cancelExisting;
}
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean checked) {
updateNotifications(mCancelExisting);
}
}
private class BackgroundPickerListener
implements BackgroundPickers.OnBackgroundPickersChangedListener {
@Override
public void onBackgroundPickersChanged(BackgroundPickers pickers) {
updateNotifications(false /* cancelExisting */);
}
}
private class NamedPresetSpinnerArrayAdapter extends ArrayAdapter<NamedPreset> {
public NamedPresetSpinnerArrayAdapter(Context context, NamedPreset[] presets) {
super(context, R.layout.simple_spinner_item, presets);
}
@Override
public View getDropDownView(int position, View convertView, ViewGroup parent) {
TextView view = (TextView) super.getDropDownView(position, convertView, parent);
view.setText(getString(getItem(position).nameResId));
return view;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
TextView view = (TextView) getLayoutInflater().inflate(
android.R.layout.simple_spinner_item, parent, false);
view.setText(getString(getItem(position).nameResId));
return view;
}
}
}