/*
* Copyright (C) 2012 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.android.settings;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.LauncherActivity.IconResizer;
import android.appwidget.AppWidgetHost;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProviderInfo;
import android.content.ActivityNotFoundException;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.IWindowManager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.GridView;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import com.android.internal.widget.LockPatternUtils;
import java.lang.ref.WeakReference;
import java.util.List;
/**
* Displays a list of {@link AppWidgetProviderInfo} widgets, along with any
* injected special widgets specified through
* {@link AppWidgetManager#EXTRA_CUSTOM_INFO} and
* {@link AppWidgetManager#EXTRA_CUSTOM_EXTRAS}.
*
* When an installed {@link AppWidgetProviderInfo} is selected, this activity
* will bind it to the given {@link AppWidgetManager#EXTRA_APPWIDGET_ID},
* otherwise it will return the requested extras.
*/
public class KeyguardAppWidgetPickActivity extends Activity
implements GridView.OnItemClickListener,
AppWidgetLoader.ItemConstructor {
private static final String TAG = "KeyguardAppWidgetPickActivity";
private static final int REQUEST_PICK_APPWIDGET = 126;
private static final int REQUEST_CREATE_APPWIDGET = 127;
private AppWidgetLoader- mAppWidgetLoader;
private List
- mItems;
private GridView mGridView;
private AppWidgetAdapter mAppWidgetAdapter;
private AppWidgetManager mAppWidgetManager;
private int mAppWidgetId;
// Might make it possible to make this be false in future
private boolean mAddingToKeyguard = true;
private Intent mResultData;
private LockPatternUtils mLockPatternUtils;
private Bundle mExtraConfigureOptions;
@Override
protected void onCreate(Bundle savedInstanceState) {
setContentView(R.layout.keyguard_appwidget_picker_layout);
super.onCreate(savedInstanceState);
// Set default return data
setResultData(RESULT_CANCELED, null);
// Read the appWidgetId passed our direction, otherwise bail if not found
final Intent intent = getIntent();
if (intent.hasExtra(AppWidgetManager.EXTRA_APPWIDGET_ID)) {
mAppWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
AppWidgetManager.INVALID_APPWIDGET_ID);
} else {
finish();
}
mExtraConfigureOptions = intent.getBundleExtra(AppWidgetManager.EXTRA_APPWIDGET_OPTIONS);
mGridView = (GridView) findViewById(R.id.widget_list);
DisplayMetrics dm = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dm);
int maxGridWidth = getResources().getDimensionPixelSize(
R.dimen.keyguard_appwidget_picker_max_width);
if (maxGridWidth < dm.widthPixels) {
mGridView.getLayoutParams().width = maxGridWidth;
}
mAppWidgetManager = AppWidgetManager.getInstance(this);
mAppWidgetLoader = new AppWidgetLoader
- (this, mAppWidgetManager, this);
mItems = mAppWidgetLoader.getItems(getIntent());
mAppWidgetAdapter = new AppWidgetAdapter(this, mItems);
mGridView.setAdapter(mAppWidgetAdapter);
mGridView.setOnItemClickListener(this);
mLockPatternUtils = new LockPatternUtils(this); // TEMP-- we want to delete this
}
/**
* Convenience method for setting the result code and intent. This method
* correctly injects the {@link AppWidgetManager#EXTRA_APPWIDGET_ID} that
* most hosts expect returned.
*/
void setResultData(int code, Intent intent) {
Intent result = intent != null ? intent : new Intent();
result.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mAppWidgetId);
mResultData = result;
setResult(code, result);
}
/**
* Item that appears in the AppWidget picker grid.
*/
public static class Item implements AppWidgetLoader.LabelledItem {
protected static IconResizer sResizer;
CharSequence label;
int appWidgetPreviewId;
int iconId;
String packageName;
String className;
Bundle extras;
private WidgetPreviewLoader mWidgetPreviewLoader;
private Context mContext;
/**
* Create a list item from given label and icon.
*/
Item(Context context, CharSequence label) {
this.label = label;
mContext = context;
}
void loadWidgetPreview(ImageView v) {
mWidgetPreviewLoader = new WidgetPreviewLoader(mContext, v);
mWidgetPreviewLoader.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, (Void[]) null);
}
void cancelLoadingWidgetPreview() {
if (mWidgetPreviewLoader != null) {
mWidgetPreviewLoader.cancel(false);
mWidgetPreviewLoader = null;
}
}
/**
* Build the {@link Intent} described by this item. If this item
* can't create a valid {@link android.content.ComponentName}, it will return
* {@link Intent#ACTION_CREATE_SHORTCUT} filled with the item label.
*/
Intent getIntent() {
Intent intent = new Intent();
if (packageName != null && className != null) {
// Valid package and class, so fill details as normal intent
intent.setClassName(packageName, className);
if (extras != null) {
intent.putExtras(extras);
}
} else {
// No valid package or class, so treat as shortcut with label
intent.setAction(Intent.ACTION_CREATE_SHORTCUT);
intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, label);
}
return intent;
}
public CharSequence getLabel() {
return label;
}
class WidgetPreviewLoader extends AsyncTask {
private Resources mResources;
private PackageManager mPackageManager;
private int mIconDpi;
private ImageView mView;
public WidgetPreviewLoader(Context context, ImageView v) {
super();
mResources = context.getResources();
mPackageManager = context.getPackageManager();
ActivityManager activityManager =
(ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
mIconDpi = activityManager.getLauncherLargeIconDensity();
mView = v;
}
public Void doInBackground(Void... params) {
if (!isCancelled()) {
int appWidgetPreviewWidth =
mResources.getDimensionPixelSize(R.dimen.appwidget_preview_width);
int appWidgetPreviewHeight =
mResources.getDimensionPixelSize(R.dimen.appwidget_preview_height);
Bitmap b = getWidgetPreview(new ComponentName(packageName, className),
appWidgetPreviewId, iconId,
appWidgetPreviewWidth, appWidgetPreviewHeight);
publishProgress(b);
}
return null;
}
public void onProgressUpdate(Bitmap... values) {
if (!isCancelled()) {
Bitmap b = values[0];
mView.setImageBitmap(b);
}
}
abstract class WeakReferenceThreadLocal {
private ThreadLocal> mThreadLocal;
public WeakReferenceThreadLocal() {
mThreadLocal = new ThreadLocal>();
}
abstract T initialValue();
public void set(T t) {
mThreadLocal.set(new WeakReference(t));
}
public T get() {
WeakReference reference = mThreadLocal.get();
T obj;
if (reference == null) {
obj = initialValue();
mThreadLocal.set(new WeakReference(obj));
return obj;
} else {
obj = reference.get();
if (obj == null) {
obj = initialValue();
mThreadLocal.set(new WeakReference(obj));
}
return obj;
}
}
}
class CanvasCache extends WeakReferenceThreadLocal