One of the key parts of Android is the ability to customize your experience through components like widgets. In this tutorial I’ll go over creating a widget to silence a phone with one tap, and in Lollipop (at least with the Nexus 4) it will place the phone into priority mode and silence the ringer, allowing the user to still get their notifications without a vibration. All code for this app can be found on GitHub.
The first thing we’re going to want to do is set up our manifest. Under the applications node, we’ll add a receiver and service.
<receiver android:name=".SilenceRingerWidget">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data android:name="android.appwidget.provider"
android:resource="@xml/silence_ringer_widget" />
</receiver>
<service android:name=".SilenceRingerService" />
SilenceRingerService
is responsible for the actual background work that our widget performs. The receiver is an extension of AppWidgetProvider
, which is a special extension of BroadcastReceiver
for app widgets. This allows it to be set to listen for APPWIDGET_UPDATE
from the system. The meta-data provided is an appwidget-provider
xml file that simply sets the layout for the widget, refresh rate and size.
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
context.startService(new Intent(context, SilenceRingerService.class));
}
SilenceRingerService
is where the bulk of this widget is handled. onStartCommand
silences the phone, builds the remote view and then kills the service until the widget button is pressed again.
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
silencePhone();
RemoteViews views = buildViews();
updateWidget( views );
stopSelf();
return START_NOT_STICKY;
}
silencePhone()
uses the AudioManager
to silence the device, and because of Lollipop we also include a thread that starts up after a second and does the same action a second time, because Lollipop first places the device into Priority mode without silencing the device, then silences the ringer after the second setRingerMode call.
private void silencePhone() {
setPriorityAndSilence();
new Thread( new Runnable() {
@Override
public void run() {
try {
Thread.sleep( 1000 );
} catch( InterruptedException e ) {
}
setPriorityAndSilence();
}
} ).run();
}
private void setPriorityAndSilence() {
AudioManager audioManager;
audioManager = (AudioManager) getBaseContext().getSystemService( Context.AUDIO_SERVICE );
audioManager.setRingerMode( AudioManager.RINGER_MODE_SILENT );
}
The last part of onStartCommand
that we need to look at has to do with RemoteViews
. We simply grab the button from our layout file and set a pending intent to it that will start up SilenceRingerService
again, and associate it with our widget.
private RemoteViews buildViews() {
RemoteViews views = new RemoteViews( getPackageName(), R.layout.widget_silence_ringer );
PendingIntent silenceIntent = PendingIntent.getService( this, 0, new Intent( this, SilenceRingerService.class ), 0 );
views.setOnClickPendingIntent( R.id.button_silence, silenceIntent );
return views;
}
private void updateWidget( RemoteViews views ) {
AppWidgetManager manager = AppWidgetManager.getInstance( this );
ComponentName widget = new ComponentName( this, SilenceRingerWidget.class );
manager.updateAppWidget( widget, views );
}
Now we have a simple widget put together that can be expanded on to fit other situations that may come up for you as a developer. Enjoy!
Originally published on http://ptrprograms.blogspot.com/.
Author: Paul Trebilcox-Ruiz