Android Lock Screen Widget

Android Lock Screen Widget

Lock screen interaction is difficult. Android allows basic operations with two window flags (FLAG_SHOW_WHEN_LOCKED and FLAG_DISMISS_KEYGUARD). FLAG_SHOW_WHEN_LOCKED works pretty consistently in that it will show on top of the lock screen even when security is enabled (the security isn't bypassed, you can't switch to another non-FLAG_SHOW_WHEN_LOCKED window).

If you're just doing something temporary, like while music is playing or similar, you'll probably mostly be okay. If you're trying to create a custom lock screen then there's a lot of unusual interactions on all the different android platforms. ("Help! I can't turn off my alarm without rebooting my HTC phone").

getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);

http://developer.android.com/reference/android/view/WindowManager.LayoutParams.html

FLAG_SHOW_WHEN_LOCKED

Window flag: special flag to let windows be shown when the screen is
locked.

FLAG_DISMISS_KEYGUARD

Window flag:
when set the window will cause the keyguard to be
dismissed, only if it is not a secure
lock keyguard. Because such a keyguard
is not needed for security, it will
never re-appear if the user navigates
to another window (in contrast to
FLAG_SHOW_WHEN_LOCKED, which will only
temporarily hide both secure and
non-secure keyguards but ensure they
reappear when the user moves to
another UI that doesn't hide them). If
the keyguard is currently active and
is secure (requires an unlock pattern)
than the user will still need to
confirm it before seeing this window,
unless FLAG_SHOW_WHEN_LOCKED has also
been set.
Constant Value: 4194304 (0x00400000)

How to create a custom lock screen widget (I just want to display a button)


API Levels

Lock-screen widgets were introduced in API 17 (4.2), and removed in API 21 (5.0). They are not supported on other official releases.


Basic Widget

I wrote a simple widget as a demo tutorial - it contains all the boilerplate code required for a widget, and very little else:

  • WiFi Widget Demo (github)
  • WiFi Widget (Play store)

I wrote it in such a way to make it easy for anyone to remove the "wifi" related code, and adapt it to their own widget requirements. It might be perfect for you to look at, and relatively simple to add a single button to it.


Lock-screen / Keyguard Widget

There are 2 changes to make it work as a lock-screen widget:

  • updating the widgetCategory to include keyguard
  • adding an initialKeyguardLayout

These changes are done in the ./res/xml/widget_info.xml file, as seen below:

<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:initialKeyguardLayout="@layout/widget"
android:initialLayout="@layout/widget"
android:minHeight="40dp"
android:minWidth="250dp"
android:updatePeriodMillis="0"
android:widgetCategory="home_screen|keyguard" >
</appwidget-provider>

I do not know if it is possible to integrate the camera into your own lock-screen widget. Clicking on a lock-screen widget normally requires the user to unlock the device before the click works.

Lollipop android lock screen widget

Lock screen widgets do not exist in either of the Android Developer Preview builds of Android 5.0 so they are effectively gone. However, WIDGET_CATEGORY_KEYGUARD has not yet been deprecated. Whether this is an oversight or not is anyone's guess. There does not appear to be any gesture, area, or anything else (such as anything in the Settings app) in the Android 5.0 builds so far that would indicate support for lock screen widgets.

It appears the main case for lock screen widgets is suggested to be handled by notifications, similar to how music controls have changed - the old RemoteControlClient based controls used to take up the same place as lock screen widgets but have been completely deprecated.

Android lock-screen Widget in Flutter?

App Widget layouts are based on RemoteViews, which do not support many types of view widgets. Because FlutterView extends SurfaceView to get access to low-level graphics APIs, it can't be embedded in an app widget.

To quote CommonsWare: "At best, you can try to write your own home screen implementation that does this." But that is a much bigger project than you probably had in mind.

Android Provide Different Layout for AppWidget at Lock Screen

If you know home screen widget implementation, it's easy.
From the code below you can figure out how to use different layout for lock screen and home screen to display the current time every second.

Create different layout for different widgets

@layout/widget_keyguard //For lock screen widget

@layout/widget_home //For home screen widget

Note: Use one TextView with id time_view on both the layouts to display the time

xml/widget_info.xml

<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:initialKeyguardLayout="@layout/widget_keyguard" // layout for lock screen
android:initialLayout="@layout/widget_home" // layout for lock screen (if not provided) & home screen
android:minHeight="100dp"
android:minWidth="300dp"
android:previewImage="@drawable/ic_launcher"
android:resizeMode="none"
android:updatePeriodMillis="180000"
android:widgetCategory="keyguard|home_screen" > //Enable widgets on both home screen and lock screen
</appwidget-provider>

AppWidgetProvider.java

    public class TestAppWidgetProvider extends AppWidgetProvider {

@Override
public void onDeleted(Context context, int[] appWidgetIds) {
super.onDeleted(context, appWidgetIds);
}

@Override
public void onDisabled(Context context) {

Intent intent = new Intent(context, AlarmManagerBroadcastReceiver.class);

PendingIntent sender = PendingIntent
.getBroadcast(context, 0, intent, 0);

AlarmManager am = (AlarmManager) context
.getSystemService(Context.ALARM_SERVICE);
am.cancel(sender); //When all the widgets are disabled, do not forget to cancel the service

super.onDisabled(context);
}

@Override
public void onEnabled(Context context) {

super.onEnabled(context);

Toast.makeText(context, "Widget Enabled", Toast.LENGTH_SHORT).show();

//AlarmManager to update the widgets
Intent intent = new Intent(context, AlarmManagerBroadcastReceiver.class);

PendingIntent p_intent = PendingIntent.getBroadcast(context, 0, intent,
0);
AlarmManager am = (AlarmManager) context
.getSystemService(Context.ALARM_SERVICE);

// Here I am updating the widgets every second (1000 ms) , you can use however you want
am.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(),
1000, p_intent);

}

@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
int[] appWidgetIds) {

Toast.makeText(context, "Widget Updated", Toast.LENGTH_SHORT).show();

ComponentName thisWidget = new ComponentName(context,
TestAppWidgetProvider.class);

for (int widgetId : appWidgetManager.getAppWidgetIds(thisWidget)) {

Bundle myOptions = appWidgetManager.getAppWidgetOptions(widgetId);
int category = myOptions.getInt(
AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY, -1);

RemoteViews remoteViews;
if (category == AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD) {
// Get the remote views
remoteViews = new RemoteViews(context.getPackageName(),
R.layout.widget_keyguard);
}

else {
remoteViews = new RemoteViews(context.getPackageName(),
R.layout.widget_home);
}

SimpleDateFormat dateFormat = new SimpleDateFormat(
"HH:mm:ss", Locale.US);
// use TextView with time_view id on both home screen & lock screen layouts
remoteViews.setTextViewText(R.id.time_view,
dateFormat.format(new Date(System.currentTimeMillis())));
appWidgetManager.updateAppWidget(widgetId, remoteViews);
}
}

@Override
public void onAppWidgetOptionsChanged(Context context,
AppWidgetManager appWidgetManager, int appWidgetId,
Bundle newOptions) {
}

}

AlarmManagerBroadcastReceiver class

    public class AlarmManagerBroadcastReceiver extends BroadcastReceiver {

@Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub


ComponentName thiswidget = new ComponentName(context,
TestAppWidgetProvider.class);

AppWidgetManager appWidgetManager = AppWidgetManager
.getInstance(context);


for (int widgetId : appWidgetManager.getAppWidgetIds(thiswidget)) {
Bundle myOptions = appWidgetManager.getAppWidgetOptions(widgetId);
int category = myOptions.getInt(
AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY, -1);

RemoteViews remoteViews;
if (category == AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD) {
// Get the remote views
Log.d("Widget", "Lockscreen widget");
remoteViews = new RemoteViews(context.getPackageName(),
R.layout.widget_keyguard);
}

else {
Log.d("Widget", "Homescreen widget");
remoteViews = new RemoteViews(context.getPackageName(),
R.layout.widget_home);
}
SimpleDateFormat dateFormat = new SimpleDateFormat(
"HH:mm:ss", Locale.US);

// use TextView with time_view id on both home screen & lock screen layouts
remoteViews.setTextViewText(R.id.time_view,
dateFormat.format(new Date(System.currentTimeMillis())));

appWidgetManager.updateAppWidget(widgetId, remoteViews);
}

}

}

Finally, do not forget to update the manifest file

        <application
...

<receiver android:name=".AlarmManagerBroadcastReceiver" />
<receiver android:name=".TestAppWidgetProvider" >
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>

<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/widget_info" />
</receiver>

.....
</application>

that's it.

I hope it'll help you to solve your problem



Related Topics



Leave a reply



Submit