621 lines
21 KiB
Java
621 lines
21 KiB
Java
![]() |
/*
|
||
|
* Copyright (C) 2009 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 android.appwidget;
|
||
|
|
||
|
import android.annotation.NonNull;
|
||
|
import android.annotation.Nullable;
|
||
|
import android.app.Activity;
|
||
|
import android.compat.annotation.UnsupportedAppUsage;
|
||
|
import android.content.ActivityNotFoundException;
|
||
|
import android.content.Context;
|
||
|
import android.content.IntentSender;
|
||
|
import android.content.pm.PackageManager;
|
||
|
import android.os.Binder;
|
||
|
import android.os.Build;
|
||
|
import android.os.Bundle;
|
||
|
import android.os.Handler;
|
||
|
import android.os.IBinder;
|
||
|
import android.os.Looper;
|
||
|
import android.os.Message;
|
||
|
import android.os.Process;
|
||
|
import android.os.RemoteException;
|
||
|
import android.os.ServiceManager;
|
||
|
import android.util.DisplayMetrics;
|
||
|
import android.util.Log;
|
||
|
import android.util.SparseArray;
|
||
|
import android.widget.RemoteViews;
|
||
|
import android.widget.RemoteViews.InteractionHandler;
|
||
|
|
||
|
import com.android.internal.R;
|
||
|
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.
|
||
|
*/
|
||
|
public class AppWidgetHost {
|
||
|
|
||
|
private static final String TAG = "AppWidgetHost";
|
||
|
|
||
|
static final int HANDLE_UPDATE = 1;
|
||
|
static final int HANDLE_PROVIDER_CHANGED = 2;
|
||
|
static final int HANDLE_PROVIDERS_CHANGED = 3;
|
||
|
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
|
||
|
static final int HANDLE_VIEW_DATA_CHANGED = 4;
|
||
|
static final int HANDLE_APP_WIDGET_REMOVED = 5;
|
||
|
static final int HANDLE_VIEW_UPDATE_DEFERRED = 6;
|
||
|
|
||
|
final static Object sServiceLock = new Object();
|
||
|
@UnsupportedAppUsage
|
||
|
static IAppWidgetService sService;
|
||
|
static boolean sServiceInitialized = false;
|
||
|
private DisplayMetrics mDisplayMetrics;
|
||
|
|
||
|
private String mContextOpPackageName;
|
||
|
@UnsupportedAppUsage
|
||
|
private final Handler mHandler;
|
||
|
private final int mHostId;
|
||
|
private final Callbacks mCallbacks;
|
||
|
private final SparseArray<AppWidgetHostListener> mListeners = new SparseArray<>();
|
||
|
private InteractionHandler mInteractionHandler;
|
||
|
|
||
|
static class Callbacks extends IAppWidgetHost.Stub {
|
||
|
private final WeakReference<Handler> mWeakHandler;
|
||
|
|
||
|
public Callbacks(Handler handler) {
|
||
|
mWeakHandler = new WeakReference<>(handler);
|
||
|
}
|
||
|
|
||
|
public void updateAppWidget(int appWidgetId, RemoteViews views) {
|
||
|
if (isLocalBinder() && views != null) {
|
||
|
views = views.clone();
|
||
|
}
|
||
|
Handler handler = mWeakHandler.get();
|
||
|
if (handler == null) {
|
||
|
return;
|
||
|
}
|
||
|
Message msg = handler.obtainMessage(HANDLE_UPDATE, appWidgetId, 0, views);
|
||
|
msg.sendToTarget();
|
||
|
}
|
||
|
|
||
|
public void providerChanged(int appWidgetId, AppWidgetProviderInfo info) {
|
||
|
if (isLocalBinder() && info != null) {
|
||
|
info = info.clone();
|
||
|
}
|
||
|
Handler handler = mWeakHandler.get();
|
||
|
if (handler == null) {
|
||
|
return;
|
||
|
}
|
||
|
Message msg = handler.obtainMessage(HANDLE_PROVIDER_CHANGED,
|
||
|
appWidgetId, 0, info);
|
||
|
msg.sendToTarget();
|
||
|
}
|
||
|
|
||
|
public void appWidgetRemoved(int appWidgetId) {
|
||
|
Handler handler = mWeakHandler.get();
|
||
|
if (handler == null) {
|
||
|
return;
|
||
|
}
|
||
|
handler.obtainMessage(HANDLE_APP_WIDGET_REMOVED, appWidgetId, 0).sendToTarget();
|
||
|
}
|
||
|
|
||
|
public void providersChanged() {
|
||
|
Handler handler = mWeakHandler.get();
|
||
|
if (handler == null) {
|
||
|
return;
|
||
|
}
|
||
|
handler.obtainMessage(HANDLE_PROVIDERS_CHANGED).sendToTarget();
|
||
|
}
|
||
|
|
||
|
public void viewDataChanged(int appWidgetId, int viewId) {
|
||
|
Handler handler = mWeakHandler.get();
|
||
|
if (handler == null) {
|
||
|
return;
|
||
|
}
|
||
|
Message msg = handler.obtainMessage(HANDLE_VIEW_DATA_CHANGED,
|
||
|
appWidgetId, viewId);
|
||
|
msg.sendToTarget();
|
||
|
}
|
||
|
|
||
|
public void updateAppWidgetDeferred(int appWidgetId) {
|
||
|
Handler handler = mWeakHandler.get();
|
||
|
if (handler == null) {
|
||
|
return;
|
||
|
}
|
||
|
Message msg = handler.obtainMessage(HANDLE_VIEW_UPDATE_DEFERRED, appWidgetId, 0, null);
|
||
|
msg.sendToTarget();
|
||
|
}
|
||
|
|
||
|
private static boolean isLocalBinder() {
|
||
|
return Process.myPid() == Binder.getCallingPid();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
class UpdateHandler extends Handler {
|
||
|
public UpdateHandler(Looper looper) {
|
||
|
super(looper);
|
||
|
}
|
||
|
|
||
|
public void handleMessage(Message msg) {
|
||
|
switch (msg.what) {
|
||
|
case HANDLE_UPDATE: {
|
||
|
updateAppWidgetView(msg.arg1, (RemoteViews)msg.obj);
|
||
|
break;
|
||
|
}
|
||
|
case HANDLE_APP_WIDGET_REMOVED: {
|
||
|
dispatchOnAppWidgetRemoved(msg.arg1);
|
||
|
break;
|
||
|
}
|
||
|
case HANDLE_PROVIDER_CHANGED: {
|
||
|
onProviderChanged(msg.arg1, (AppWidgetProviderInfo)msg.obj);
|
||
|
break;
|
||
|
}
|
||
|
case HANDLE_PROVIDERS_CHANGED: {
|
||
|
onProvidersChanged();
|
||
|
break;
|
||
|
}
|
||
|
case HANDLE_VIEW_DATA_CHANGED: {
|
||
|
viewDataChanged(msg.arg1, msg.arg2);
|
||
|
break;
|
||
|
}
|
||
|
case HANDLE_VIEW_UPDATE_DEFERRED: {
|
||
|
updateAppWidgetDeferred(msg.arg1);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public AppWidgetHost(Context context, int hostId) {
|
||
|
this(context, hostId, null, context.getMainLooper());
|
||
|
}
|
||
|
|
||
|
@Nullable
|
||
|
private AppWidgetHostListener getListener(final int appWidgetId) {
|
||
|
AppWidgetHostListener tempListener = null;
|
||
|
synchronized (mListeners) {
|
||
|
tempListener = mListeners.get(appWidgetId);
|
||
|
}
|
||
|
return tempListener;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @hide
|
||
|
*/
|
||
|
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
|
||
|
public AppWidgetHost(Context context, int hostId, InteractionHandler handler, Looper looper) {
|
||
|
mContextOpPackageName = context.getOpPackageName();
|
||
|
mHostId = hostId;
|
||
|
mInteractionHandler = handler;
|
||
|
mHandler = new UpdateHandler(looper);
|
||
|
mCallbacks = new Callbacks(mHandler);
|
||
|
mDisplayMetrics = context.getResources().getDisplayMetrics();
|
||
|
bindService(context);
|
||
|
}
|
||
|
|
||
|
private static void bindService(Context context) {
|
||
|
synchronized (sServiceLock) {
|
||
|
if (sServiceInitialized) {
|
||
|
return;
|
||
|
}
|
||
|
sServiceInitialized = true;
|
||
|
PackageManager packageManager = context.getPackageManager();
|
||
|
if (!packageManager.hasSystemFeature(PackageManager.FEATURE_APP_WIDGETS)
|
||
|
&& !context.getResources().getBoolean(R.bool.config_enableAppWidgetService)) {
|
||
|
return;
|
||
|
}
|
||
|
IBinder b = ServiceManager.getService(Context.APPWIDGET_SERVICE);
|
||
|
sService = IAppWidgetService.Stub.asInterface(b);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Start receiving onAppWidgetChanged calls for your AppWidgets. Call this when your activity
|
||
|
* becomes visible, i.e. from onStart() in your Activity.
|
||
|
*/
|
||
|
public void startListening() {
|
||
|
if (sService == null) {
|
||
|
return;
|
||
|
}
|
||
|
final int[] idsToUpdate;
|
||
|
synchronized (mListeners) {
|
||
|
int n = mListeners.size();
|
||
|
idsToUpdate = new int[n];
|
||
|
for (int i = 0; i < n; i++) {
|
||
|
idsToUpdate[i] = mListeners.keyAt(i);
|
||
|
}
|
||
|
}
|
||
|
List<PendingHostUpdate> updates;
|
||
|
try {
|
||
|
updates = sService.startListening(
|
||
|
mCallbacks, mContextOpPackageName, mHostId, idsToUpdate).getList();
|
||
|
}
|
||
|
catch (RemoteException e) {
|
||
|
throw new RuntimeException("system server dead?", e);
|
||
|
}
|
||
|
|
||
|
int N = updates.size();
|
||
|
for (int i = 0; i < N; i++) {
|
||
|
PendingHostUpdate update = updates.get(i);
|
||
|
switch (update.type) {
|
||
|
case PendingHostUpdate.TYPE_VIEWS_UPDATE:
|
||
|
updateAppWidgetView(update.appWidgetId, update.views);
|
||
|
break;
|
||
|
case PendingHostUpdate.TYPE_PROVIDER_CHANGED:
|
||
|
onProviderChanged(update.appWidgetId, update.widgetInfo);
|
||
|
break;
|
||
|
case PendingHostUpdate.TYPE_VIEW_DATA_CHANGED:
|
||
|
viewDataChanged(update.appWidgetId, update.viewId);
|
||
|
break;
|
||
|
case PendingHostUpdate.TYPE_APP_WIDGET_REMOVED:
|
||
|
dispatchOnAppWidgetRemoved(update.appWidgetId);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Stop receiving onAppWidgetChanged calls for your AppWidgets. Call this when your activity is
|
||
|
* no longer visible, i.e. from onStop() in your Activity.
|
||
|
*/
|
||
|
public void stopListening() {
|
||
|
if (sService == null) {
|
||
|
return;
|
||
|
}
|
||
|
try {
|
||
|
sService.stopListening(mContextOpPackageName, mHostId);
|
||
|
}
|
||
|
catch (RemoteException e) {
|
||
|
throw new RuntimeException("system server dead?", e);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get a appWidgetId for a host in the calling process.
|
||
|
*
|
||
|
* @return a appWidgetId
|
||
|
*/
|
||
|
public int allocateAppWidgetId() {
|
||
|
if (sService == null) {
|
||
|
return -1;
|
||
|
}
|
||
|
try {
|
||
|
return sService.allocateAppWidgetId(mContextOpPackageName, mHostId);
|
||
|
}
|
||
|
catch (RemoteException e) {
|
||
|
throw new RuntimeException("system server dead?", e);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Starts an app widget provider configure activity for result on behalf of the caller.
|
||
|
* Use this method if the provider is in another profile as you are not allowed to start
|
||
|
* an activity in another profile. You can optionally provide a request code that is
|
||
|
* returned in {@link Activity#onActivityResult(int, int, android.content.Intent)} and
|
||
|
* an options bundle to be passed to the started activity.
|
||
|
* <p>
|
||
|
* Note that the provided app widget has to be bound for this method to work.
|
||
|
* </p>
|
||
|
*
|
||
|
* @param activity The activity from which to start the configure one.
|
||
|
* @param appWidgetId The bound app widget whose provider's config activity to start.
|
||
|
* @param requestCode Optional request code retuned with the result.
|
||
|
* @param intentFlags Optional intent flags.
|
||
|
*
|
||
|
* @throws android.content.ActivityNotFoundException If the activity is not found.
|
||
|
*
|
||
|
* @see AppWidgetProviderInfo#getProfile()
|
||
|
*/
|
||
|
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);
|
||
|
if (intentSender != null) {
|
||
|
activity.startIntentSenderForResult(intentSender, requestCode, null, 0, 0, 0,
|
||
|
options);
|
||
|
} else {
|
||
|
throw new ActivityNotFoundException();
|
||
|
}
|
||
|
} catch (IntentSender.SendIntentException e) {
|
||
|
throw new ActivityNotFoundException();
|
||
|
} catch (RemoteException e) {
|
||
|
throw new RuntimeException("system server dead?", e);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Set the visibiity of all widgets associated with this host to hidden
|
||
|
*
|
||
|
* @hide
|
||
|
*/
|
||
|
public void setAppWidgetHidden() {
|
||
|
if (sService == null) {
|
||
|
return;
|
||
|
}
|
||
|
try {
|
||
|
sService.setAppWidgetHidden(mContextOpPackageName, mHostId);
|
||
|
} catch (RemoteException e) {
|
||
|
throw new RuntimeException("System server dead?", e);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Set the host's interaction handler.
|
||
|
*
|
||
|
* @hide
|
||
|
*/
|
||
|
public void setInteractionHandler(InteractionHandler interactionHandler) {
|
||
|
mInteractionHandler = interactionHandler;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* 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 {
|
||
|
return sService.getAppWidgetIdsForHost(mContextOpPackageName, mHostId);
|
||
|
} catch (RemoteException e) {
|
||
|
throw new RuntimeException("system server dead?", e);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Stop listening to changes for this AppWidget.
|
||
|
*/
|
||
|
public void deleteAppWidgetId(int appWidgetId) {
|
||
|
if (sService == null) {
|
||
|
return;
|
||
|
}
|
||
|
removeListener(appWidgetId);
|
||
|
try {
|
||
|
sService.deleteAppWidgetId(mContextOpPackageName, appWidgetId);
|
||
|
} catch (RemoteException e) {
|
||
|
throw new RuntimeException("system server dead?", e);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Remove all records about this host from the AppWidget manager.
|
||
|
* <ul>
|
||
|
* <li>Call this when initializing your database, as it might be because of a data wipe.</li>
|
||
|
* <li>Call this to have the AppWidget manager release all resources associated with your
|
||
|
* host. Any future calls about this host will cause the records to be re-allocated.</li>
|
||
|
* </ul>
|
||
|
*/
|
||
|
public void deleteHost() {
|
||
|
if (sService == null) {
|
||
|
return;
|
||
|
}
|
||
|
try {
|
||
|
sService.deleteHost(mContextOpPackageName, mHostId);
|
||
|
}
|
||
|
catch (RemoteException e) {
|
||
|
throw new RuntimeException("system server dead?", e);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Remove all records about all hosts for your package.
|
||
|
* <ul>
|
||
|
* <li>Call this when initializing your database, as it might be because of a data wipe.</li>
|
||
|
* <li>Call this to have the AppWidget manager release all resources associated with your
|
||
|
* host. Any future calls about this host will cause the records to be re-allocated.</li>
|
||
|
* </ul>
|
||
|
*/
|
||
|
public static void deleteAllHosts() {
|
||
|
if (sService == null) {
|
||
|
return;
|
||
|
}
|
||
|
try {
|
||
|
sService.deleteAllHosts();
|
||
|
}
|
||
|
catch (RemoteException e) {
|
||
|
throw new RuntimeException("system server dead?", e);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Create the AppWidgetHostView for the given widget.
|
||
|
* The AppWidgetHost retains a pointer to the newly-created View.
|
||
|
*/
|
||
|
public final AppWidgetHostView createView(Context context, int appWidgetId,
|
||
|
AppWidgetProviderInfo appWidget) {
|
||
|
if (sService == null) {
|
||
|
return null;
|
||
|
}
|
||
|
AppWidgetHostView view = onCreateView(context, appWidgetId, appWidget);
|
||
|
view.setInteractionHandler(mInteractionHandler);
|
||
|
view.setAppWidget(appWidgetId, appWidget);
|
||
|
setListener(appWidgetId, view);
|
||
|
|
||
|
return view;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Called to create the AppWidgetHostView. Override to return a custom subclass if you
|
||
|
* need it. {@more}
|
||
|
*/
|
||
|
protected AppWidgetHostView onCreateView(Context context, int appWidgetId,
|
||
|
AppWidgetProviderInfo appWidget) {
|
||
|
return new AppWidgetHostView(context, mInteractionHandler);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Called when the AppWidget provider for a AppWidget has been upgraded to a new apk.
|
||
|
*/
|
||
|
protected void onProviderChanged(int appWidgetId, AppWidgetProviderInfo appWidget) {
|
||
|
AppWidgetHostListener v = getListener(appWidgetId);
|
||
|
|
||
|
// Convert complex to dp -- we are getting the AppWidgetProviderInfo from the
|
||
|
// AppWidgetService, which doesn't have our context, hence we need to do the
|
||
|
// conversion here.
|
||
|
appWidget.updateDimensions(mDisplayMetrics);
|
||
|
if (v != null) {
|
||
|
v.onUpdateProviderInfo(appWidget);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* This interface specifies the actions to be performed on the app widget based on the calls
|
||
|
* from the service
|
||
|
*
|
||
|
* @hide
|
||
|
*/
|
||
|
public interface AppWidgetHostListener {
|
||
|
|
||
|
/**
|
||
|
* This function is called when the service want to reset the app widget provider info
|
||
|
* @param appWidget The new app widget provider info
|
||
|
*
|
||
|
* @hide
|
||
|
*/
|
||
|
void onUpdateProviderInfo(@Nullable AppWidgetProviderInfo appWidget);
|
||
|
|
||
|
/**
|
||
|
* This function is called when the {@code RemoteViews} of the app widget is updated
|
||
|
* @param views The new {@code RemoteViews} to be set for the app widget
|
||
|
*
|
||
|
* @hide
|
||
|
*/
|
||
|
void updateAppWidget(@Nullable RemoteViews views);
|
||
|
|
||
|
/**
|
||
|
* Called for the listener to handle deferred {@code RemoteViews} updates. Default
|
||
|
* implementation is to update the widget directly.
|
||
|
* @param packageName The package name used for uid verification on the service side
|
||
|
* @param appWidgetId The widget id of the listener
|
||
|
*
|
||
|
* @hide
|
||
|
*/
|
||
|
default void updateAppWidgetDeferred(String packageName, int appWidgetId) {
|
||
|
RemoteViews latestViews = null;
|
||
|
try {
|
||
|
latestViews = sService.getAppWidgetViews(packageName, appWidgetId);
|
||
|
} catch (Exception e) {
|
||
|
Log.e(TAG, "updateAppWidgetDeferred: ", e);
|
||
|
}
|
||
|
updateAppWidget(latestViews);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* This function is called when the view ID is changed for the app widget
|
||
|
* @param viewId The new view ID to be be set for the widget
|
||
|
*
|
||
|
* @hide
|
||
|
*/
|
||
|
void onViewDataChanged(int viewId);
|
||
|
}
|
||
|
|
||
|
void dispatchOnAppWidgetRemoved(int appWidgetId) {
|
||
|
removeListener(appWidgetId);
|
||
|
onAppWidgetRemoved(appWidgetId);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Called when the app widget is removed for appWidgetId
|
||
|
* @param appWidgetId
|
||
|
*/
|
||
|
public void onAppWidgetRemoved(int appWidgetId) {
|
||
|
// Does nothing
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Called when the set of available widgets changes (ie. widget containing packages
|
||
|
* are added, updated or removed, or widget components are enabled or disabled.)
|
||
|
*/
|
||
|
protected void onProvidersChanged() {
|
||
|
// Does nothing
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Create an AppWidgetHostListener for the given widget.
|
||
|
* The AppWidgetHost retains a pointer to the newly-created listener.
|
||
|
* @param appWidgetId The ID of the app widget for which to add the listener
|
||
|
* @param listener The listener interface that deals with actions towards the widget view
|
||
|
* @hide
|
||
|
*/
|
||
|
public void setListener(int appWidgetId, @NonNull AppWidgetHostListener listener) {
|
||
|
synchronized (mListeners) {
|
||
|
mListeners.put(appWidgetId, listener);
|
||
|
}
|
||
|
RemoteViews views = null;
|
||
|
try {
|
||
|
views = sService.getAppWidgetViews(mContextOpPackageName, appWidgetId);
|
||
|
} catch (RemoteException e) {
|
||
|
throw new RuntimeException("system server dead?", e);
|
||
|
}
|
||
|
listener.updateAppWidget(views);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Delete the listener for the given widget
|
||
|
* @param appWidgetId The ID of the app widget for which the listener is to be deleted
|
||
|
|
||
|
* @hide
|
||
|
*/
|
||
|
public void removeListener(int appWidgetId) {
|
||
|
synchronized (mListeners) {
|
||
|
mListeners.remove(appWidgetId);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void updateAppWidgetView(int appWidgetId, RemoteViews views) {
|
||
|
AppWidgetHostListener v = getListener(appWidgetId);
|
||
|
if (v != null) {
|
||
|
v.updateAppWidget(views);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void viewDataChanged(int appWidgetId, int viewId) {
|
||
|
AppWidgetHostListener v = getListener(appWidgetId);
|
||
|
if (v != null) {
|
||
|
v.onViewDataChanged(viewId);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private void updateAppWidgetDeferred(int appWidgetId) {
|
||
|
AppWidgetHostListener v = getListener(appWidgetId);
|
||
|
if (v == null) {
|
||
|
Log.e(TAG, "updateAppWidgetDeferred: null listener for id: " + appWidgetId);
|
||
|
return;
|
||
|
}
|
||
|
v.updateAppWidgetDeferred(mContextOpPackageName, appWidgetId);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Clear the list of Views that have been created by this AppWidgetHost.
|
||
|
*/
|
||
|
protected void clearViews() {
|
||
|
synchronized (mListeners) {
|
||
|
mListeners.clear();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|