Fix crashes in AppWidgetHost when app_widgets is not supported

Even though an app is supposed to declare android.software.app_widgets
when relying on the widgets API, some apps still use this API without
declaring the feature.  Previously AppWidgetHost relied on having an
AppWidgetService available, without checking for feature development
before dereferencing the service.

This stubs out the AppWidgetHost interface when the app_widgets feature
is not available.

Bug: 28847209
Test: run nova launcher, observe no crash

Change-Id: Idaf46de990fffa6c6a03562f8e097c0a6a320c8a
(cherry picked from commit 0536802defc7df6edb22e076b1147d0d919da0f8)
This commit is contained in:
Elijah Taylor
2016-07-11 14:28:06 -07:00
committed by Luis Hector Chavez
parent 360eea897f
commit 6022aa57d3

View File

@@ -16,15 +16,13 @@
package android.appwidget;
import java.lang.ref.WeakReference;
import java.util.List;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.IntentSender;
import android.content.pm.PackageManager;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
@@ -42,6 +40,9 @@ import android.widget.RemoteViews.OnClickHandler;
import com.android.internal.appwidget.IAppWidgetHost;
import com.android.internal.appwidget.IAppWidgetService;
import java.lang.ref.WeakReference;
import java.util.List;
/**
* AppWidgetHost provides the interaction with the AppWidget service for apps,
* like the home screen, that want to embed AppWidgets in their UI.
@@ -55,6 +56,7 @@ public class AppWidgetHost {
final static Object sServiceLock = new Object();
static IAppWidgetService sService;
static boolean sServiceInitialized = false;
private DisplayMetrics mDisplayMetrics;
private String mContextOpPackageName;
@@ -160,15 +162,21 @@ public class AppWidgetHost {
mHandler = new UpdateHandler(looper);
mCallbacks = new Callbacks(mHandler);
mDisplayMetrics = context.getResources().getDisplayMetrics();
bindService();
bindService(context);
}
private static void bindService() {
private static void bindService(Context context) {
synchronized (sServiceLock) {
if (sService == null) {
IBinder b = ServiceManager.getService(Context.APPWIDGET_SERVICE);
sService = IAppWidgetService.Stub.asInterface(b);
if (sServiceInitialized) {
return;
}
sServiceInitialized = true;
if (!context.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_APP_WIDGETS)) {
return;
}
IBinder b = ServiceManager.getService(Context.APPWIDGET_SERVICE);
sService = IAppWidgetService.Stub.asInterface(b);
}
}
@@ -177,6 +185,9 @@ public class AppWidgetHost {
* becomes visible, i.e. from onStart() in your Activity.
*/
public void startListening() {
if (sService == null) {
return;
}
final int[] idsToUpdate;
synchronized (mViews) {
int N = mViews.size();
@@ -215,6 +226,9 @@ public class AppWidgetHost {
* no longer visible, i.e. from onStop() in your Activity.
*/
public void stopListening() {
if (sService == null) {
return;
}
try {
sService.stopListening(mContextOpPackageName, mHostId);
}
@@ -229,6 +243,9 @@ public class AppWidgetHost {
* @return a appWidgetId
*/
public int allocateAppWidgetId() {
if (sService == null) {
return -1;
}
try {
return sService.allocateAppWidgetId(mContextOpPackageName, mHostId);
}
@@ -258,6 +275,9 @@ public class AppWidgetHost {
*/
public final void startAppWidgetConfigureActivityForResult(@NonNull Activity activity,
int appWidgetId, int intentFlags, int requestCode, @Nullable Bundle options) {
if (sService == null) {
return;
}
try {
IntentSender intentSender = sService.createAppWidgetConfigIntentSender(
mContextOpPackageName, appWidgetId, intentFlags);
@@ -278,10 +298,10 @@ public class AppWidgetHost {
* Gets a list of all the appWidgetIds that are bound to the current host
*/
public int[] getAppWidgetIds() {
if (sService == null) {
return new int[0];
}
try {
if (sService == null) {
bindService();
}
return sService.getAppWidgetIdsForHost(mContextOpPackageName, mHostId);
} catch (RemoteException e) {
throw new RuntimeException("system server dead?", e);
@@ -292,6 +312,9 @@ public class AppWidgetHost {
* Stop listening to changes for this AppWidget.
*/
public void deleteAppWidgetId(int appWidgetId) {
if (sService == null) {
return;
}
synchronized (mViews) {
mViews.remove(appWidgetId);
try {
@@ -312,6 +335,9 @@ public class AppWidgetHost {
* </ul>
*/
public void deleteHost() {
if (sService == null) {
return;
}
try {
sService.deleteHost(mContextOpPackageName, mHostId);
}
@@ -329,6 +355,9 @@ public class AppWidgetHost {
* </ul>
*/
public static void deleteAllHosts() {
if (sService == null) {
return;
}
try {
sService.deleteAllHosts();
}
@@ -343,6 +372,9 @@ public class AppWidgetHost {
*/
public final AppWidgetHostView createView(Context context, int appWidgetId,
AppWidgetProviderInfo appWidget) {
if (sService == null) {
return null;
}
AppWidgetHostView view = onCreateView(context, appWidgetId, appWidget);
view.setOnClickHandler(mOnClickHandler);
view.setAppWidget(appWidgetId, appWidget);