summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--AndroidManifest.xml12
-rw-r--r--res/drawable-hdpi/appwidget_item_bg_normal.9.pngbin0 -> 468 bytes
-rw-r--r--res/drawable-hdpi/appwidget_item_bg_pressed.9.pngbin0 -> 553 bytes
-rw-r--r--res/drawable-mdpi/appwidget_item_bg_normal.9.pngbin0 -> 332 bytes
-rw-r--r--res/drawable-mdpi/appwidget_item_bg_pressed.9.pngbin0 -> 394 bytes
-rw-r--r--res/drawable-xhdpi/appwidget_item_bg_normal.9.pngbin0 -> 591 bytes
-rw-r--r--res/drawable-xhdpi/appwidget_item_bg_pressed.9.pngbin0 -> 737 bytes
-rw-r--r--res/drawable/appwidget_item_bg.xml23
-rwxr-xr-xres/layout/keyguard_appwidget_item.xml35
-rw-r--r--res/layout/keyguard_appwidget_pick_layout.xml27
-rw-r--r--res/values/strings.xml9
-rw-r--r--res/xml/security_settings_biometric_weak.xml6
-rw-r--r--res/xml/security_settings_chooser.xml6
-rw-r--r--res/xml/security_settings_password.xml6
-rw-r--r--res/xml/security_settings_pattern.xml6
-rw-r--r--res/xml/security_settings_pin.xml6
-rw-r--r--src/com/android/settings/ActivityPicker.java8
-rw-r--r--src/com/android/settings/AppWidgetLoader.java182
-rw-r--r--src/com/android/settings/AppWidgetPickActivity.java249
-rw-r--r--src/com/android/settings/KeyguardAppWidgetPickActivity.java579
-rw-r--r--src/com/android/settings/SecuritySettings.java131
21 files changed, 925 insertions, 360 deletions
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index a11a948..f2e51a1 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -1315,6 +1315,18 @@
</intent-filter>
</activity>
+ <!-- Special picker for keyguard widgets -->
+ <activity android:name="KeyguardAppWidgetPickActivity"
+ android:label="@string/widget_picker_title"
+ android:theme="@android:style/Theme.Holo.Wallpaper.NoTitleBar"
+ android:permission="android.permission.BIND_KEYGUARD_APPWIDGET"
+ android:finishOnCloseSystemDialogs="true">
+ <intent-filter>
+ <action android:name="android.appwidget.action.KEYGUARD_APPWIDGET_PICK" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </activity>
+
<activity android:name="UsageStats" android:label="@string/usage_stats_label"
android:taskAffinity="com.android.settings"
android:parentActivityName="Settings">
diff --git a/res/drawable-hdpi/appwidget_item_bg_normal.9.png b/res/drawable-hdpi/appwidget_item_bg_normal.9.png
new file mode 100644
index 0000000..baff858
--- /dev/null
+++ b/res/drawable-hdpi/appwidget_item_bg_normal.9.png
Binary files differ
diff --git a/res/drawable-hdpi/appwidget_item_bg_pressed.9.png b/res/drawable-hdpi/appwidget_item_bg_pressed.9.png
new file mode 100644
index 0000000..7ec33dd
--- /dev/null
+++ b/res/drawable-hdpi/appwidget_item_bg_pressed.9.png
Binary files differ
diff --git a/res/drawable-mdpi/appwidget_item_bg_normal.9.png b/res/drawable-mdpi/appwidget_item_bg_normal.9.png
new file mode 100644
index 0000000..976083f
--- /dev/null
+++ b/res/drawable-mdpi/appwidget_item_bg_normal.9.png
Binary files differ
diff --git a/res/drawable-mdpi/appwidget_item_bg_pressed.9.png b/res/drawable-mdpi/appwidget_item_bg_pressed.9.png
new file mode 100644
index 0000000..8f340d3
--- /dev/null
+++ b/res/drawable-mdpi/appwidget_item_bg_pressed.9.png
Binary files differ
diff --git a/res/drawable-xhdpi/appwidget_item_bg_normal.9.png b/res/drawable-xhdpi/appwidget_item_bg_normal.9.png
new file mode 100644
index 0000000..b26f1d2
--- /dev/null
+++ b/res/drawable-xhdpi/appwidget_item_bg_normal.9.png
Binary files differ
diff --git a/res/drawable-xhdpi/appwidget_item_bg_pressed.9.png b/res/drawable-xhdpi/appwidget_item_bg_pressed.9.png
new file mode 100644
index 0000000..3871689
--- /dev/null
+++ b/res/drawable-xhdpi/appwidget_item_bg_pressed.9.png
Binary files differ
diff --git a/res/drawable/appwidget_item_bg.xml b/res/drawable/appwidget_item_bg.xml
new file mode 100644
index 0000000..b9de6d4
--- /dev/null
+++ b/res/drawable/appwidget_item_bg.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <item android:state_pressed="true"
+ android:drawable="@drawable/appwidget_item_bg_pressed" />
+
+ <item android:drawable="@drawable/appwidget_item_bg_normal" />
+</selector>
diff --git a/res/layout/keyguard_appwidget_item.xml b/res/layout/keyguard_appwidget_item.xml
new file mode 100755
index 0000000..7280098
--- /dev/null
+++ b/res/layout/keyguard_appwidget_item.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" >
+ <TextView
+ android:id="@+id/icon_and_label"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="8dip"
+ android:layout_marginRight="8dip"
+ android:layout_marginTop="4dip"
+ android:layout_marginBottom="4dip"
+ android:background="@drawable/appwidget_item_bg"
+ android:minHeight="?android:attr/listPreferredItemHeightSmall"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:gravity="center_vertical"
+ android:drawablePadding="8dip"
+ android:paddingStart="11dip"
+ android:paddingEnd="11dip" />
+</FrameLayout>
diff --git a/res/layout/keyguard_appwidget_pick_layout.xml b/res/layout/keyguard_appwidget_pick_layout.xml
new file mode 100644
index 0000000..feb85a5
--- /dev/null
+++ b/res/layout/keyguard_appwidget_pick_layout.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/layout_root"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical" >
+ <GridView android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1"
+ android:listSelector="@android:color/transparent"
+ android:id="@+id/widget_list" />
+</LinearLayout>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 2248c23..d6abe94 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -808,15 +808,6 @@
<!-- Title for PreferenceScreen to launch picker for security method when there is none [CHAR LIMIT=22] -->
<string name="unlock_set_unlock_launch_picker_title">Screen lock</string>
- <!-- Title for PreferenceScreen to launch picker for a user-selected widget that will live on lock screen [CHAR LIMIT=22] -->
- <string name="choose_user_selected_lockscreen_widget_picker_title">Add widget</string>
-
- <!-- String to display if there is no user-selected widget on lock screen [CHAR LIMIT=22] -->
- <string name="widget_none">None</string>
-
- <!-- String to display if the clock status widget is selected (it is the default) [CHAR LIMIT=22] -->
- <string name="widget_default">Clock</string>
-
<!-- Title for PreferenceScreen to change security method: None/Pattern/PIN/Password [CHAR LIMIT=22] -->
<string name="unlock_set_unlock_launch_picker_change_title">Change lock screen</string>
diff --git a/res/xml/security_settings_biometric_weak.xml b/res/xml/security_settings_biometric_weak.xml
index 489a200..c830e6f 100644
--- a/res/xml/security_settings_biometric_weak.xml
+++ b/res/xml/security_settings_biometric_weak.xml
@@ -52,12 +52,6 @@
android:title="@string/lockpattern_settings_enable_power_button_instantly_locks"/>
<PreferenceScreen
- android:key="choose_user_selected_lockscreen_widget"
- android:title="@string/choose_user_selected_lockscreen_widget_picker_title"
- android:summary=""
- android:persistent="false"/>
-
- <PreferenceScreen
android:fragment="com.android.settings.OwnerInfoSettings"
android:key="owner_info_settings"
android:title="@string/owner_info_settings_title"
diff --git a/res/xml/security_settings_chooser.xml b/res/xml/security_settings_chooser.xml
index 98422ba..60d3a9f 100644
--- a/res/xml/security_settings_chooser.xml
+++ b/res/xml/security_settings_chooser.xml
@@ -27,12 +27,6 @@
android:persistent="false"/>
<PreferenceScreen
- android:key="choose_user_selected_lockscreen_widget"
- android:title="@string/choose_user_selected_lockscreen_widget_picker_title"
- android:summary=""
- android:persistent="false"/>
-
- <PreferenceScreen
android:fragment="com.android.settings.OwnerInfoSettings"
android:key="owner_info_settings"
android:title="@string/owner_info_settings_title"
diff --git a/res/xml/security_settings_password.xml b/res/xml/security_settings_password.xml
index 8374a13..0e9c71d 100644
--- a/res/xml/security_settings_password.xml
+++ b/res/xml/security_settings_password.xml
@@ -39,12 +39,6 @@
android:title="@string/lockpattern_settings_enable_power_button_instantly_locks"/>
<PreferenceScreen
- android:key="choose_user_selected_lockscreen_widget"
- android:title="@string/choose_user_selected_lockscreen_widget_picker_title"
- android:summary=""
- android:persistent="false"/>
-
- <PreferenceScreen
android:fragment="com.android.settings.OwnerInfoSettings"
android:key="owner_info_settings"
android:title="@string/owner_info_settings_title"
diff --git a/res/xml/security_settings_pattern.xml b/res/xml/security_settings_pattern.xml
index 8015785..d47a99d 100644
--- a/res/xml/security_settings_pattern.xml
+++ b/res/xml/security_settings_pattern.xml
@@ -43,12 +43,6 @@
android:title="@string/lockpattern_settings_enable_power_button_instantly_locks"/>
<PreferenceScreen
- android:key="choose_user_selected_lockscreen_widget"
- android:title="@string/choose_user_selected_lockscreen_widget_picker_title"
- android:summary=""
- android:persistent="false"/>
-
- <PreferenceScreen
android:fragment="com.android.settings.OwnerInfoSettings"
android:key="owner_info_settings"
android:title="@string/owner_info_settings_title"
diff --git a/res/xml/security_settings_pin.xml b/res/xml/security_settings_pin.xml
index 70e95bd..d44200f 100644
--- a/res/xml/security_settings_pin.xml
+++ b/res/xml/security_settings_pin.xml
@@ -39,12 +39,6 @@
android:title="@string/lockpattern_settings_enable_power_button_instantly_locks"/>
<PreferenceScreen
- android:key="choose_user_selected_lockscreen_widget"
- android:title="@string/choose_user_selected_lockscreen_widget_picker_title"
- android:summary=""
- android:persistent="false"/>
-
- <PreferenceScreen
android:fragment="com.android.settings.OwnerInfoSettings"
android:key="owner_info_settings"
android:title="@string/owner_info_settings_title"
diff --git a/src/com/android/settings/ActivityPicker.java b/src/com/android/settings/ActivityPicker.java
index ac79cea..edbccc3 100644
--- a/src/com/android/settings/ActivityPicker.java
+++ b/src/com/android/settings/ActivityPicker.java
@@ -201,7 +201,7 @@ public class ActivityPicker extends AlertActivity implements
/**
* Item that appears in a {@link PickAdapter} list.
*/
- public static class Item {
+ public static class Item implements AppWidgetLoader.LabelledItem {
protected static IconResizer sResizer;
protected IconResizer getResizer(Context context) {
@@ -262,6 +262,10 @@ public class ActivityPicker extends AlertActivity implements
}
return intent;
}
+
+ public CharSequence getLabel() {
+ return label;
+ }
}
private final LayoutInflater mInflater;
@@ -471,5 +475,5 @@ public class ActivityPicker extends AlertActivity implements
public int getOpacity() {
return PixelFormat.TRANSLUCENT;
}
- }
+ }
}
diff --git a/src/com/android/settings/AppWidgetLoader.java b/src/com/android/settings/AppWidgetLoader.java
new file mode 100644
index 0000000..9155e60
--- /dev/null
+++ b/src/com/android/settings/AppWidgetLoader.java
@@ -0,0 +1,182 @@
+/*
+ * 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.appwidget.AppWidgetManager;
+import android.appwidget.AppWidgetProviderInfo;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Parcelable;
+import android.util.Log;
+
+import java.text.Collator;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+public class AppWidgetLoader<Item extends AppWidgetLoader.LabelledItem> {
+ private static final String TAG = "AppWidgetAdapter";
+ private static final boolean LOGD = AppWidgetPickActivity.LOGD;
+
+ private Context mContext;
+ private AppWidgetManager mAppWidgetManager;
+ ItemConstructor<Item> mItemConstructor;
+
+ interface LabelledItem {
+ CharSequence getLabel();
+ }
+
+ public AppWidgetLoader(Context context, AppWidgetManager appWidgetManager,
+ ItemConstructor<Item> itemConstructor) {
+ mContext = context;
+ mAppWidgetManager = appWidgetManager;
+ mItemConstructor = itemConstructor;
+ }
+
+ /**
+ * Create list entries for any custom widgets requested through
+ * {@link AppWidgetManager#EXTRA_CUSTOM_INFO}.
+ */
+ void putCustomAppWidgets(List<Item> items, Intent intent) {
+ // get and validate the extras they gave us
+ ArrayList<AppWidgetProviderInfo> customInfo = null;
+ ArrayList<Bundle> customExtras = null;
+ try_custom_items: {
+ customInfo = intent.getParcelableArrayListExtra(AppWidgetManager.EXTRA_CUSTOM_INFO);
+ if (customInfo == null || customInfo.size() == 0) {
+ Log.i(TAG, "EXTRA_CUSTOM_INFO not present.");
+ break try_custom_items;
+ }
+
+ int customInfoSize = customInfo.size();
+ for (int i=0; i<customInfoSize; i++) {
+ Parcelable p = customInfo.get(i);
+ if (p == null || !(p instanceof AppWidgetProviderInfo)) {
+ customInfo = null;
+ Log.e(TAG, "error using EXTRA_CUSTOM_INFO index=" + i);
+ break try_custom_items;
+ }
+ }
+
+ customExtras = intent.getParcelableArrayListExtra(AppWidgetManager.EXTRA_CUSTOM_EXTRAS);
+ if (customExtras == null) {
+ customInfo = null;
+ Log.e(TAG, "EXTRA_CUSTOM_INFO without EXTRA_CUSTOM_EXTRAS");
+ break try_custom_items;
+ }
+
+ int customExtrasSize = customExtras.size();
+ if (customInfoSize != customExtrasSize) {
+ customInfo = null;
+ customExtras = null;
+ Log.e(TAG, "list size mismatch: EXTRA_CUSTOM_INFO: " + customInfoSize
+ + " EXTRA_CUSTOM_EXTRAS: " + customExtrasSize);
+ break try_custom_items;
+ }
+
+
+ for (int i=0; i<customExtrasSize; i++) {
+ Parcelable p = customExtras.get(i);
+ if (p == null || !(p instanceof Bundle)) {
+ customInfo = null;
+ customExtras = null;
+ Log.e(TAG, "error using EXTRA_CUSTOM_EXTRAS index=" + i);
+ break try_custom_items;
+ }
+ }
+ }
+
+ if (LOGD) Log.d(TAG, "Using " + customInfo.size() + " custom items");
+ putAppWidgetItems(customInfo, customExtras, items, 0, true);
+ }
+
+
+ /**
+ * Create list entries for the given {@link AppWidgetProviderInfo} widgets,
+ * inserting extras if provided.
+ */
+ void putAppWidgetItems(List<AppWidgetProviderInfo> appWidgets,
+ List<Bundle> customExtras, List<Item> items, int categoryFilter,
+ boolean ignoreFilter) {
+ if (appWidgets == null) return;
+ final int size = appWidgets.size();
+ for (int i = 0; i < size; i++) {
+ AppWidgetProviderInfo info = appWidgets.get(i);
+
+ // We remove any widgets whose category isn't included in the filter
+ if (!ignoreFilter && (info.widgetCategory & categoryFilter) == 0) {
+ continue;
+ }
+
+ Item item = mItemConstructor.createItem(mContext, info,
+ customExtras != null ? customExtras.get(i) : null);
+
+ items.add(item);
+ }
+ }
+
+ public interface ItemConstructor<Item> {
+ Item createItem(Context context, AppWidgetProviderInfo info, Bundle extras);
+ }
+
+
+ /**
+ * Build and return list of items to be shown in dialog. This will mix both
+ * installed {@link AppWidgetProviderInfo} and those provided through
+ * {@link AppWidgetManager#EXTRA_CUSTOM_INFO}, sorting them alphabetically.
+ */
+ protected List<Item> getItems(Intent intent) {
+ boolean sortCustomAppWidgets =
+ intent.getBooleanExtra(AppWidgetManager.EXTRA_CUSTOM_SORT, true);
+
+ List<Item> items = new ArrayList<Item>();
+
+ // Default category is home screen
+ int categoryFilter = intent.getIntExtra(AppWidgetManager.EXTRA_CATEGORY_FILTER,
+ AppWidgetProviderInfo.WIDGET_CATEGORY_HOME_SCREEN);
+
+ putInstalledAppWidgets(items, categoryFilter);
+
+ // Sort all items together by label
+ if (sortCustomAppWidgets) {
+ putCustomAppWidgets(items, intent);
+ }
+ Collections.sort(items, new Comparator<Item>() {
+ Collator mCollator = Collator.getInstance();
+
+ public int compare(Item lhs, Item rhs) {
+ return mCollator.compare(lhs.getLabel(), rhs.getLabel());
+ }
+ });
+ if (!sortCustomAppWidgets) {
+ List<Item> customItems = new ArrayList<Item>();
+ putCustomAppWidgets(customItems, intent);
+ items.addAll(customItems);
+ }
+ return items;
+ }
+
+ /**
+ * Create list entries for installed {@link AppWidgetProviderInfo} widgets.
+ */
+ void putInstalledAppWidgets(List<Item> items, int categoryFilter) {
+ List<AppWidgetProviderInfo> installed = mAppWidgetManager.getInstalledProviders();
+ putAppWidgetItems(installed, null, items, categoryFilter, false);
+ }
+}
diff --git a/src/com/android/settings/AppWidgetPickActivity.java b/src/com/android/settings/AppWidgetPickActivity.java
index 953d10c..2bd62c0 100644
--- a/src/com/android/settings/AppWidgetPickActivity.java
+++ b/src/com/android/settings/AppWidgetPickActivity.java
@@ -18,6 +18,7 @@ package com.android.settings;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProviderInfo;
+import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
@@ -25,15 +26,11 @@ import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
-import android.os.Parcelable;
-import android.os.SystemProperties;
import android.util.DisplayMetrics;
import android.util.Log;
-import java.text.Collator;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
+import com.android.settings.ActivityPicker.PickAdapter;
+
import java.util.List;
/**
@@ -46,12 +43,11 @@ import java.util.List;
* will bind it to the given {@link AppWidgetManager#EXTRA_APPWIDGET_ID},
* otherwise it will return the requested extras.
*/
-public class AppWidgetPickActivity extends ActivityPicker {
+public class AppWidgetPickActivity extends ActivityPicker
+ implements AppWidgetLoader.ItemConstructor<PickAdapter.Item>{
private static final String TAG = "AppWidgetPickActivity";
- private static final boolean LOGD = false;
+ static final boolean LOGD = false;
- private PackageManager mPackageManager;
- private AppWidgetManager mAppWidgetManager;
List<PickAdapter.Item> mItems;
/**
@@ -59,15 +55,16 @@ public class AppWidgetPickActivity extends ActivityPicker {
* activity is binding.
*/
private int mAppWidgetId;
-
- // Enable testing launcher widgets in keyguard. For testing purposes only.
- private final boolean mIgnoreFilter = false || SystemProperties.getBoolean(
- "ro.keyguard_ignore_filter", false);
+ private AppWidgetLoader<PickAdapter.Item> mAppWidgetLoader;
+ private AppWidgetManager mAppWidgetManager;
+ private PackageManager mPackageManager;
@Override
public void onCreate(Bundle icicle) {
mPackageManager = getPackageManager();
mAppWidgetManager = AppWidgetManager.getInstance(this);
+ mAppWidgetLoader = new AppWidgetLoader<PickAdapter.Item>
+ (this, mAppWidgetManager, this);
super.onCreate(icicle);
@@ -85,69 +82,69 @@ public class AppWidgetPickActivity extends ActivityPicker {
}
/**
- * Create list entries for any custom widgets requested through
- * {@link AppWidgetManager#EXTRA_CUSTOM_INFO}.
+ * Build and return list of items to be shown in dialog. This will mix both
+ * installed {@link AppWidgetProviderInfo} and those provided through
+ * {@link AppWidgetManager#EXTRA_CUSTOM_INFO}, sorting them alphabetically.
*/
- void putCustomAppWidgets(List<PickAdapter.Item> items) {
- final Bundle extras = getIntent().getExtras();
-
- // get and validate the extras they gave us
- ArrayList<AppWidgetProviderInfo> customInfo = null;
- ArrayList<Bundle> customExtras = null;
- try_custom_items: {
- customInfo = extras.getParcelableArrayList(AppWidgetManager.EXTRA_CUSTOM_INFO);
- if (customInfo == null || customInfo.size() == 0) {
- Log.i(TAG, "EXTRA_CUSTOM_INFO not present.");
- break try_custom_items;
- }
-
- int customInfoSize = customInfo.size();
- for (int i=0; i<customInfoSize; i++) {
- Parcelable p = customInfo.get(i);
- if (p == null || !(p instanceof AppWidgetProviderInfo)) {
- customInfo = null;
- Log.e(TAG, "error using EXTRA_CUSTOM_INFO index=" + i);
- break try_custom_items;
- }
- }
-
- customExtras = extras.getParcelableArrayList(AppWidgetManager.EXTRA_CUSTOM_EXTRAS);
- if (customExtras == null) {
- customInfo = null;
- Log.e(TAG, "EXTRA_CUSTOM_INFO without EXTRA_CUSTOM_EXTRAS");
- break try_custom_items;
- }
-
- int customExtrasSize = customExtras.size();
- if (customInfoSize != customExtrasSize) {
- Log.e(TAG, "list size mismatch: EXTRA_CUSTOM_INFO: " + customInfoSize
- + " EXTRA_CUSTOM_EXTRAS: " + customExtrasSize);
- break try_custom_items;
- }
+ @Override
+ protected List<PickAdapter.Item> getItems() {
+ mItems = mAppWidgetLoader.getItems(getIntent());
+ return mItems;
+ }
+ @Override
+ public PickAdapter.Item createItem(Context context, AppWidgetProviderInfo info, Bundle extras) {
+ CharSequence label = info.label;
+ Drawable icon = null;
- for (int i=0; i<customExtrasSize; i++) {
- Parcelable p = customExtras.get(i);
- if (p == null || !(p instanceof Bundle)) {
- customInfo = null;
- customExtras = null;
- Log.e(TAG, "error using EXTRA_CUSTOM_EXTRAS index=" + i);
- break try_custom_items;
+ if (info.icon != 0) {
+ try {
+ final Resources res = context.getResources();
+ final int density = res.getDisplayMetrics().densityDpi;
+ int iconDensity;
+ switch (density) {
+ case DisplayMetrics.DENSITY_MEDIUM:
+ iconDensity = DisplayMetrics.DENSITY_LOW;
+ case DisplayMetrics.DENSITY_TV:
+ iconDensity = DisplayMetrics.DENSITY_MEDIUM;
+ case DisplayMetrics.DENSITY_HIGH:
+ iconDensity = DisplayMetrics.DENSITY_MEDIUM;
+ case DisplayMetrics.DENSITY_XHIGH:
+ iconDensity = DisplayMetrics.DENSITY_HIGH;
+ case DisplayMetrics.DENSITY_XXHIGH:
+ iconDensity = DisplayMetrics.DENSITY_XHIGH;
+ default:
+ // The density is some abnormal value. Return some other
+ // abnormal value that is a reasonable scaling of it.
+ iconDensity = (int)((density*0.75f)+.5f);
}
+ Resources packageResources = mPackageManager.
+ getResourcesForApplication(info.provider.getPackageName());
+ icon = packageResources.getDrawableForDensity(info.icon, iconDensity);
+ } catch (NameNotFoundException e) {
+ Log.w(TAG, "Can't load icon drawable 0x" + Integer.toHexString(info.icon)
+ + " for provider: " + info.provider);
+ }
+ if (icon == null) {
+ Log.w(TAG, "Can't load icon drawable 0x" + Integer.toHexString(info.icon)
+ + " for provider: " + info.provider);
}
}
- if (LOGD) Log.d(TAG, "Using " + customInfo.size() + " custom items");
- putAppWidgetItems(customInfo, customExtras, items, 0, 0, true);
+ PickAdapter.Item item = new PickAdapter.Item(context, label, icon);
+ item.packageName = info.provider.getPackageName();
+ item.className = info.provider.getClassName();
+ item.extras = extras;
+ return item;
}
-
+
/**
* {@inheritDoc}
*/
@Override
public void onClick(DialogInterface dialog, int which) {
Intent intent = getIntentForPosition(which);
- PickAdapter.Item item = (PickAdapter.Item) mItems.get(which);
+ PickAdapter.Item item = mItems.get(which);
int result;
if (item.extras != null) {
@@ -173,134 +170,10 @@ public class AppWidgetPickActivity extends ActivityPicker {
}
setResultData(result, null);
}
- finish();
- }
-
- /**
- * Create list entries for the given {@link AppWidgetProviderInfo} widgets,
- * inserting extras if provided.
- */
- void putAppWidgetItems(List<AppWidgetProviderInfo> appWidgets,
- List<Bundle> customExtras, List<PickAdapter.Item> items, int categoryFilter,
- int featuresFilter, boolean ignoreFilters) {
- if (appWidgets == null) return;
- final int size = appWidgets.size();
- for (int i = 0; i < size; i++) {
- AppWidgetProviderInfo info = appWidgets.get(i);
-
- // We remove any widgets whose category isn't included in the filter
- if (!ignoreFilters && (info.widgetCategory & categoryFilter) == 0) {
- continue;
- }
-
- // We remove any widgets who don't have all the features in the features filter
- if (!ignoreFilters && (info.widgetFeatures & featuresFilter) != featuresFilter) {
- continue;
- }
-
- CharSequence label = info.label;
- Drawable icon = null;
-
- if (info.icon != 0) {
- try {
- final Resources res = getResources();
- final int density = res.getDisplayMetrics().densityDpi;
- int iconDensity;
- switch (density) {
- case DisplayMetrics.DENSITY_MEDIUM:
- iconDensity = DisplayMetrics.DENSITY_LOW;
- case DisplayMetrics.DENSITY_TV:
- iconDensity = DisplayMetrics.DENSITY_MEDIUM;
- case DisplayMetrics.DENSITY_HIGH:
- iconDensity = DisplayMetrics.DENSITY_MEDIUM;
- case DisplayMetrics.DENSITY_XHIGH:
- iconDensity = DisplayMetrics.DENSITY_HIGH;
- case DisplayMetrics.DENSITY_XXHIGH:
- iconDensity = DisplayMetrics.DENSITY_XHIGH;
- default:
- // The density is some abnormal value. Return some other
- // abnormal value that is a reasonable scaling of it.
- iconDensity = (int)((density*0.75f)+.5f);
- }
- Resources packageResources = mPackageManager.
- getResourcesForApplication(info.provider.getPackageName());
- icon = packageResources.getDrawableForDensity(info.icon, iconDensity);
- } catch (NameNotFoundException e) {
- Log.w(TAG, "Can't load icon drawable 0x" + Integer.toHexString(info.icon)
- + " for provider: " + info.provider);
- }
- if (icon == null) {
- Log.w(TAG, "Can't load icon drawable 0x" + Integer.toHexString(info.icon)
- + " for provider: " + info.provider);
- }
- }
-
- PickAdapter.Item item = new PickAdapter.Item(this, label, icon);
-
- item.packageName = info.provider.getPackageName();
- item.className = info.provider.getClassName();
-
- if (customExtras != null) {
- item.extras = customExtras.get(i);
- }
-
- items.add(item);
- }
- }
-
- /**
- * Build and return list of items to be shown in dialog. This will mix both
- * installed {@link AppWidgetProviderInfo} and those provided through
- * {@link AppWidgetManager#EXTRA_CUSTOM_INFO}, sorting them alphabetically.
- */
- @Override
- protected List<PickAdapter.Item> getItems() {
- final Intent intent = getIntent();
- boolean sortCustomAppWidgets =
- intent.getBooleanExtra(AppWidgetManager.EXTRA_CUSTOM_SORT, true);
-
- List<PickAdapter.Item> items = new ArrayList<PickAdapter.Item>();
-
- int categoryFilter = AppWidgetProviderInfo.WIDGET_CATEGORY_HOME_SCREEN;
- if (intent.getExtras().containsKey(AppWidgetManager.EXTRA_CATEGORY_FILTER)) {
- categoryFilter = intent.getExtras().getInt(AppWidgetManager.EXTRA_CATEGORY_FILTER);
- }
-
- // If not specified, we don't filter on any specific
- int featuresFilter = AppWidgetProviderInfo.WIDGET_FEATURES_NONE;
- if (intent.getExtras().containsKey(AppWidgetManager.EXTRA_FEATURES_FILTER)) {
- featuresFilter = intent.getExtras().getInt(AppWidgetManager.EXTRA_FEATURES_FILTER);
- }
-
- putInstalledAppWidgets(items, categoryFilter, featuresFilter);
- // Sort all items together by label
- if (sortCustomAppWidgets) {
- putCustomAppWidgets(items);
- }
- Collections.sort(items, new Comparator<PickAdapter.Item>() {
- Collator mCollator = Collator.getInstance();
-
- public int compare(PickAdapter.Item lhs, PickAdapter.Item rhs) {
- return mCollator.compare(lhs.label, rhs.label);
- }
- });
- if (!sortCustomAppWidgets) {
- List<PickAdapter.Item> customItems = new ArrayList<PickAdapter.Item>();
- putCustomAppWidgets(customItems);
- items.addAll(customItems);
- }
- mItems = items;
- return items;
+ finish();
}
- /**
- * Create list entries for installed {@link AppWidgetProviderInfo} widgets.
- */
- void putInstalledAppWidgets(List<PickAdapter.Item> items, int categoryFilter, int featuresFilter) {
- List<AppWidgetProviderInfo> installed = mAppWidgetManager.getInstalledProviders();
- putAppWidgetItems(installed, null, items, categoryFilter, featuresFilter, mIgnoreFilter );
- }
/**
* Convenience method for setting the result code and intent. This method
diff --git a/src/com/android/settings/KeyguardAppWidgetPickActivity.java b/src/com/android/settings/KeyguardAppWidgetPickActivity.java
new file mode 100644
index 0000000..0afc5b2
--- /dev/null
+++ b/src/com/android/settings/KeyguardAppWidgetPickActivity.java
@@ -0,0 +1,579 @@
+/*
+ * 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.appwidget.AppWidgetHost;
+import android.appwidget.AppWidgetManager;
+import android.appwidget.AppWidgetProviderInfo;
+import android.content.ActivityNotFoundException;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ResolveInfo;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.ColorFilter;
+import android.graphics.Paint;
+import android.graphics.PaintFlagsDrawFilter;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.PaintDrawable;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+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.TextView;
+import android.widget.Toast;
+
+import com.android.internal.widget.LockPatternUtils;
+
+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}.
+ * <p>
+ * 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<KeyguardAppWidgetPickActivity.Item> {
+ private static final String TAG = "KeyguardAppWidgetPickActivity";
+ private static final int REQUEST_PICK_APPWIDGET = 126;
+ private static final int REQUEST_CREATE_APPWIDGET = 127;
+
+ private AppWidgetLoader<Item> mAppWidgetLoader;
+ private List<Item> mItems;
+ private GridView mGridView;
+ 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 boolean mSuccess;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ setContentView(R.layout.keyguard_appwidget_pick_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();
+ }
+
+ mGridView = (GridView) findViewById(R.id.widget_list);
+ mAppWidgetManager = AppWidgetManager.getInstance(this);
+ mAppWidgetLoader = new AppWidgetLoader<Item>(this, mAppWidgetManager, this);
+ mItems = mAppWidgetLoader.getItems(getIntent());
+ AppWidgetAdapter adapter = new AppWidgetAdapter(this, mItems);
+ mGridView.setAdapter(adapter);
+ 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);
+ }
+
+ private static class EmptyDrawable extends Drawable {
+ private final int mWidth;
+ private final int mHeight;
+
+ EmptyDrawable(int width, int height) {
+ mWidth = width;
+ mHeight = height;
+ }
+
+ @Override
+ public int getIntrinsicWidth() {
+ return mWidth;
+ }
+
+ @Override
+ public int getIntrinsicHeight() {
+ return mHeight;
+ }
+
+ @Override
+ public int getMinimumWidth() {
+ return mWidth;
+ }
+
+ @Override
+ public int getMinimumHeight() {
+ return mHeight;
+ }
+
+ @Override
+ public void draw(Canvas canvas) {
+ }
+
+ @Override
+ public void setAlpha(int alpha) {
+ }
+
+ @Override
+ public void setColorFilter(ColorFilter cf) {
+ }
+
+ @Override
+ public int getOpacity() {
+ return PixelFormat.TRANSLUCENT;
+ }
+ }
+
+ /**
+ * Utility class to resize icons to match default icon size. Code is mostly
+ * borrowed from Launcher.
+ */
+ private static class IconResizer {
+ private final int mIconWidth;
+ private final int mIconHeight;
+
+ private final DisplayMetrics mMetrics;
+ private final Rect mOldBounds = new Rect();
+ private final Canvas mCanvas = new Canvas();
+
+ public IconResizer(int width, int height, DisplayMetrics metrics) {
+ mCanvas.setDrawFilter(new PaintFlagsDrawFilter(Paint.DITHER_FLAG,
+ Paint.FILTER_BITMAP_FLAG));
+
+ mMetrics = metrics;
+ mIconWidth = width;
+ mIconHeight = height;
+ }
+
+ /**
+ * Returns a Drawable representing the thumbnail of the specified Drawable.
+ * The size of the thumbnail is defined by the dimension
+ * android.R.dimen.launcher_application_icon_size.
+ *
+ * This method is not thread-safe and should be invoked on the UI thread only.
+ *
+ * @param icon The icon to get a thumbnail of.
+ *
+ * @return A thumbnail for the specified icon or the icon itself if the
+ * thumbnail could not be created.
+ */
+ public Drawable createIconThumbnail(Drawable icon) {
+ int width = mIconWidth;
+ int height = mIconHeight;
+
+ if (icon == null) {
+ return new EmptyDrawable(width, height);
+ }
+
+ try {
+ if (icon instanceof PaintDrawable) {
+ PaintDrawable painter = (PaintDrawable) icon;
+ painter.setIntrinsicWidth(width);
+ painter.setIntrinsicHeight(height);
+ } else if (icon instanceof BitmapDrawable) {
+ // Ensure the bitmap has a density.
+ BitmapDrawable bitmapDrawable = (BitmapDrawable) icon;
+ Bitmap bitmap = bitmapDrawable.getBitmap();
+ if (bitmap.getDensity() == Bitmap.DENSITY_NONE) {
+ bitmapDrawable.setTargetDensity(mMetrics);
+ }
+ }
+ int iconWidth = icon.getIntrinsicWidth();
+ int iconHeight = icon.getIntrinsicHeight();
+
+ if (iconWidth > 0 && iconHeight > 0) {
+ if (width < iconWidth || height < iconHeight) {
+ final float ratio = (float) iconWidth / iconHeight;
+
+ if (iconWidth > iconHeight) {
+ height = (int) (width / ratio);
+ } else if (iconHeight > iconWidth) {
+ width = (int) (height * ratio);
+ }
+
+ final Bitmap.Config c = icon.getOpacity() != PixelFormat.OPAQUE ?
+ Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565;
+ final Bitmap thumb = Bitmap.createBitmap(mIconWidth, mIconHeight, c);
+ final Canvas canvas = mCanvas;
+ canvas.setBitmap(thumb);
+ // Copy the old bounds to restore them later
+ // If we were to do oldBounds = icon.getBounds(),
+ // the call to setBounds() that follows would
+ // change the same instance and we would lose the
+ // old bounds
+ mOldBounds.set(icon.getBounds());
+ final int x = (mIconWidth - width) / 2;
+ final int y = (mIconHeight - height) / 2;
+ icon.setBounds(x, y, x + width, y + height);
+ icon.draw(canvas);
+ icon.setBounds(mOldBounds);
+ //noinspection deprecation
+ icon = new BitmapDrawable(thumb);
+ ((BitmapDrawable) icon).setTargetDensity(mMetrics);
+ canvas.setBitmap(null);
+ } else if (iconWidth < width && iconHeight < height) {
+ final Bitmap.Config c = Bitmap.Config.ARGB_8888;
+ final Bitmap thumb = Bitmap.createBitmap(mIconWidth, mIconHeight, c);
+ final Canvas canvas = mCanvas;
+ canvas.setBitmap(thumb);
+ mOldBounds.set(icon.getBounds());
+ final int x = (width - iconWidth) / 2;
+ final int y = (height - iconHeight) / 2;
+ icon.setBounds(x, y, x + iconWidth, y + iconHeight);
+ icon.draw(canvas);
+ icon.setBounds(mOldBounds);
+ //noinspection deprecation
+ icon = new BitmapDrawable(thumb);
+ ((BitmapDrawable) icon).setTargetDensity(mMetrics);
+ canvas.setBitmap(null);
+ }
+ }
+
+ } catch (Throwable t) {
+ icon = new EmptyDrawable(width, height);
+ }
+
+ return icon;
+ }
+ }
+
+ /**
+ * Item that appears in the AppWidget picker grid.
+ */
+ public static class Item implements AppWidgetLoader.LabelledItem {
+ protected static IconResizer sResizer;
+
+ protected IconResizer getResizer(Context context) {
+ if (sResizer == null) {
+ final Resources resources = context.getResources();
+ int size = (int) resources.getDimension(android.R.dimen.app_icon_size);
+ sResizer = new IconResizer(size, size, resources.getDisplayMetrics());
+ }
+ return sResizer;
+ }
+ CharSequence label;
+ Drawable icon;
+ String packageName;
+ String className;
+ Bundle extras;
+
+ /**
+ * Create a list item from given label and icon.
+ */
+ Item(Context context, CharSequence label, Drawable icon) {
+ this.label = label;
+ this.icon = getResizer(context).createIconThumbnail(icon);
+ }
+
+ /**
+ * Create a list item and fill it with details from the given
+ * {@link ResolveInfo} object.
+ */
+ Item(Context context, PackageManager pm, ResolveInfo resolveInfo) {
+ label = resolveInfo.loadLabel(pm);
+ if (label == null && resolveInfo.activityInfo != null) {
+ label = resolveInfo.activityInfo.name;
+ }
+
+ icon = getResizer(context).createIconThumbnail(resolveInfo.loadIcon(pm));
+ packageName = resolveInfo.activityInfo.applicationInfo.packageName;
+ className = resolveInfo.activityInfo.name;
+ }
+
+ /**
+ * 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;
+ }
+ }
+
+ @Override
+ public Item createItem(Context context, AppWidgetProviderInfo info, Bundle extras) {
+ CharSequence label = info.label;
+ Drawable icon = null;
+
+ if (info.icon != 0) {
+ try {
+ final Resources res = context.getResources();
+ final int density = res.getDisplayMetrics().densityDpi;
+ int iconDensity;
+ switch (density) {
+ case DisplayMetrics.DENSITY_MEDIUM:
+ iconDensity = DisplayMetrics.DENSITY_LOW;
+ case DisplayMetrics.DENSITY_TV:
+ iconDensity = DisplayMetrics.DENSITY_MEDIUM;
+ case DisplayMetrics.DENSITY_HIGH:
+ iconDensity = DisplayMetrics.DENSITY_MEDIUM;
+ case DisplayMetrics.DENSITY_XHIGH:
+ iconDensity = DisplayMetrics.DENSITY_HIGH;
+ case DisplayMetrics.DENSITY_XXHIGH:
+ iconDensity = DisplayMetrics.DENSITY_XHIGH;
+ default:
+ // The density is some abnormal value. Return some other
+ // abnormal value that is a reasonable scaling of it.
+ iconDensity = (int)((density*0.75f)+.5f);
+ }
+ Resources packageResources = getPackageManager().
+ getResourcesForApplication(info.provider.getPackageName());
+ icon = packageResources.getDrawableForDensity(info.icon, iconDensity);
+ } catch (NameNotFoundException e) {
+ Log.w(TAG, "Can't load icon drawable 0x" + Integer.toHexString(info.icon)
+ + " for provider: " + info.provider);
+ }
+ if (icon == null) {
+ Log.w(TAG, "Can't load icon drawable 0x" + Integer.toHexString(info.icon)
+ + " for provider: " + info.provider);
+ }
+ }
+
+ Item item = new Item(context, label, icon);
+ item.packageName = info.provider.getPackageName();
+ item.className = info.provider.getClassName();
+ item.extras = extras;
+ return item;
+ }
+
+ protected static class AppWidgetAdapter extends BaseAdapter {
+ private final LayoutInflater mInflater;
+ private final List<Item> mItems;
+
+ /**
+ * Create an adapter for the given items.
+ */
+ public AppWidgetAdapter(Context context, List<Item> items) {
+ mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ mItems = items;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int getCount() {
+ return mItems.size();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Object getItem(int position) {
+ return mItems.get(position);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public long getItemId(int position) {
+ return position;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public View getView(int position, View convertView, ViewGroup parent) {
+ if (convertView == null) {
+ convertView = mInflater.inflate(R.layout.keyguard_appwidget_item, parent, false);
+ }
+
+ Item item = (Item) getItem(position);
+ TextView textView = (TextView) convertView.findViewById(R.id.icon_and_label);
+ textView.setText(item.label);
+ textView.setCompoundDrawablesWithIntrinsicBounds(item.icon, null, null, null);
+
+ return convertView;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+ Item item = mItems.get(position);
+ Intent intent = item.getIntent();
+
+ int result;
+ if (item.extras != null) {
+ // If these extras are present it's because this entry is custom.
+ // Don't try to bind it, just pass it back to the app.
+ result = RESULT_OK;
+ setResultData(result, intent);
+ } else {
+ try {
+ Bundle options = null;
+ if (intent.getExtras() != null) {
+ options = intent.getExtras().getBundle(
+ AppWidgetManager.EXTRA_APPWIDGET_OPTIONS);
+ }
+ mAppWidgetManager.bindAppWidgetId(mAppWidgetId, intent.getComponent(), options);
+ result = RESULT_OK;
+ } catch (IllegalArgumentException e) {
+ // This is thrown if they're already bound, or otherwise somehow
+ // bogus. Set the result to canceled, and exit. The app *should*
+ // clean up at this point. We could pass the error along, but
+ // it's not clear that that's useful -- the widget will simply not
+ // appear.
+ result = RESULT_CANCELED;
+ }
+ setResultData(result, null);
+ }
+ if (mAddingToKeyguard) {
+ onActivityResult(REQUEST_PICK_APPWIDGET, result, mResultData);
+ } else {
+ finish();
+ }
+ }
+
+ protected void onDestroy() {
+ if (!mSuccess && mAddingToKeyguard &&
+ mAppWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID) {
+ AppWidgetHost.deleteAppWidgetIdForSystem(mAppWidgetId);
+ }
+ super.onDestroy();
+ }
+
+ @Override
+ public void onActivityResult(int requestCode, int resultCode, Intent data) {
+ super.onActivityResult(requestCode, resultCode, data);
+ if (requestCode == REQUEST_PICK_APPWIDGET || requestCode == REQUEST_CREATE_APPWIDGET) {
+ int appWidgetId = (data == null) ? -1 : data.getIntExtra(
+ AppWidgetManager.EXTRA_APPWIDGET_ID, -1);
+ if ((requestCode == REQUEST_PICK_APPWIDGET) &&
+ resultCode == Activity.RESULT_OK) {
+ AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(this);
+ boolean defaultWidget =
+ data.getBooleanExtra(LockPatternUtils.EXTRA_DEFAULT_WIDGET, false);
+
+ AppWidgetProviderInfo appWidget = null;
+ if (!defaultWidget) {
+ appWidget = appWidgetManager.getAppWidgetInfo(appWidgetId);
+ }
+
+ if (!defaultWidget && appWidget.configure != null) {
+ // Launch over to configure widget, if needed
+ Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_CONFIGURE);
+ intent.setComponent(appWidget.configure);
+ intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+ intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
+
+ startActivityForResultSafely(intent, REQUEST_CREATE_APPWIDGET);
+ } else {
+ // Otherwise just add it
+ if (defaultWidget) {
+ // If we selected "none", delete the allocated id
+ AppWidgetHost.deleteAppWidgetIdForSystem(appWidgetId);
+ data.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
+ LockPatternUtils.ID_DEFAULT_STATUS_WIDGET);
+ }
+ onActivityResult(REQUEST_CREATE_APPWIDGET, Activity.RESULT_OK, data);
+ }
+ } else if (requestCode == REQUEST_CREATE_APPWIDGET && resultCode == Activity.RESULT_OK) {
+ mSuccess = true;
+ mLockPatternUtils.addAppWidget(appWidgetId, 0);
+ finishDelayedAndShowLockScreen();
+ } else {
+ finishDelayedAndShowLockScreen();
+ }
+ }
+ }
+
+ private void finishDelayedAndShowLockScreen() {
+ IBinder b = ServiceManager.getService(Context.WINDOW_SERVICE);
+ IWindowManager iWm = IWindowManager.Stub.asInterface(b);
+ try {
+ iWm.lockNow(null);
+ } catch (RemoteException e) {
+ }
+
+ // Change background to all black
+ ViewGroup root = (ViewGroup) findViewById(R.id.layout_root);
+ root.setBackgroundColor(0xFF000000);
+ // Hide all children
+ final int childCount = root.getChildCount();
+ for (int i = 0; i < childCount; i++) {
+ root.getChildAt(i).setVisibility(View.INVISIBLE);
+ }
+ mGridView.postDelayed(new Runnable() {
+ public void run() {
+ finish();
+ }
+ }, 500);
+ }
+
+ void startActivityForResultSafely(Intent intent, int requestCode) {
+ try {
+ startActivityForResult(intent, requestCode);
+ } catch (ActivityNotFoundException e) {
+ Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
+ } catch (SecurityException e) {
+ Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
+ Log.e(TAG, "Settings does not have the permission to launch " + intent, e);
+ }
+ }
+}
diff --git a/src/com/android/settings/SecuritySettings.java b/src/com/android/settings/SecuritySettings.java
index 7a5118b..22812b2 100644
--- a/src/com/android/settings/SecuritySettings.java
+++ b/src/com/android/settings/SecuritySettings.java
@@ -22,20 +22,12 @@ import static android.provider.Settings.System.SCREEN_OFF_TIMEOUT;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.admin.DevicePolicyManager;
-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.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.Bundle;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.os.ServiceManager;
import android.os.UserHandle;
import android.preference.CheckBoxPreference;
import android.preference.ListPreference;
@@ -47,8 +39,6 @@ import android.provider.Settings;
import android.security.KeyStore;
import android.telephony.TelephonyManager;
import android.util.Log;
-import android.view.IWindowManager;
-import android.widget.Toast;
import com.android.internal.widget.LockPatternUtils;
@@ -65,8 +55,6 @@ public class SecuritySettings extends SettingsPreferenceFragment
// Lock Settings
private static final String KEY_UNLOCK_SET_OR_CHANGE = "unlock_set_or_change";
- private static final String KEY_CHOOSE_LOCKSCREEN_WIDGET =
- "choose_user_selected_lockscreen_widget";
private static final String KEY_BIOMETRIC_WEAK_IMPROVE_MATCHING =
"biometric_weak_improve_matching";
private static final String KEY_BIOMETRIC_WEAK_LIVELINESS = "biometric_weak_liveliness";
@@ -76,12 +64,9 @@ public class SecuritySettings extends SettingsPreferenceFragment
private static final String KEY_DEVICE_ADMIN_CATEGORY = "device_admin_category";
private static final String KEY_LOCK_AFTER_TIMEOUT = "lock_after_timeout";
private static final String KEY_OWNER_INFO_SETTINGS = "owner_info_settings";
- private static final String EXTRA_DEFAULT_WIDGET = "com.android.settings.DEFAULT_WIDGET";
private static final int SET_OR_CHANGE_LOCK_METHOD_REQUEST = 123;
private static final int CONFIRM_EXISTING_FOR_BIOMETRIC_WEAK_IMPROVE_REQUEST = 124;
private static final int CONFIRM_EXISTING_FOR_BIOMETRIC_WEAK_LIVELINESS_OFF = 125;
- private static final int REQUEST_PICK_APPWIDGET = 126;
- private static final int REQUEST_CREATE_APPWIDGET = 127;
// Misc Settings
private static final String KEY_SIM_LOCK = "sim_lock";
@@ -421,68 +406,6 @@ public class SecuritySettings extends SettingsPreferenceFragment
}
}
- void startActivityForResultSafely(Intent intent, int requestCode) {
- try {
- startActivityForResult(intent, requestCode);
- } catch (ActivityNotFoundException e) {
- Toast.makeText(getActivity(), R.string.activity_not_found, Toast.LENGTH_SHORT).show();
- } catch (SecurityException e) {
- Toast.makeText(getActivity(), R.string.activity_not_found, Toast.LENGTH_SHORT).show();
- Log.e(TAG, "Settings does not have the permission to launch " + intent, e);
- }
- }
-
- private void launchPickActivityIntent(int featuresFilter, int defaultLabelId, int defaultIconId,
- ComponentName defaultComponentName, String defaultTag, int widgetType) {
- // Create intent to pick widget
- Intent pickIntent = new Intent(AppWidgetManager.ACTION_APPWIDGET_PICK);
-
- // Found in KeyguardHostView.java
- final int KEYGUARD_HOST_ID = 0x4B455947;
- int appWidgetId = AppWidgetHost.allocateAppWidgetIdForSystem(KEYGUARD_HOST_ID);
- if (appWidgetId != -1) {
- pickIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
- pickIntent.putExtra(AppWidgetManager.EXTRA_CUSTOM_SORT, false);
- pickIntent.putExtra(AppWidgetManager.EXTRA_CATEGORY_FILTER,
- AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD);
- if (featuresFilter != AppWidgetProviderInfo.WIDGET_FEATURES_NONE) {
- pickIntent.putExtra(AppWidgetManager.EXTRA_FEATURES_FILTER, featuresFilter);
- }
-
- // Add an entry for "none" to let someone select no widget
- AppWidgetProviderInfo defaultInfo = new AppWidgetProviderInfo();
- ArrayList<AppWidgetProviderInfo> extraInfos = new ArrayList<AppWidgetProviderInfo>();
- defaultInfo.label = getResources().getString(defaultLabelId);
- defaultInfo.icon = defaultIconId;
- defaultInfo.provider = defaultComponentName;
- extraInfos.add(defaultInfo);
-
- ArrayList<Bundle> extraExtras = new ArrayList<Bundle>();
- Bundle b = new Bundle();
- b.putBoolean(defaultTag, true);
- extraExtras.add(b);
-
- // Launch the widget picker
- pickIntent.putExtra(AppWidgetManager.EXTRA_CUSTOM_INFO, extraInfos);
- pickIntent.putExtra(AppWidgetManager.EXTRA_CUSTOM_EXTRAS, extraExtras);
- pickIntent.putExtra(Intent.EXTRA_INTENT, getBaseIntent());
- startActivityForResult(pickIntent, widgetType);
- } else {
- Log.e(TAG, "Unable to allocate an AppWidget id in lock screen");
- }
- }
-
- private Intent getBaseIntent() {
- Intent baseIntent = new Intent(Intent.ACTION_MAIN, null);
- baseIntent.addCategory(Intent.CATEGORY_DEFAULT);
-
- Bundle options = new Bundle();
- options.putInt(AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY,
- AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD);
- baseIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_OPTIONS, options);
- return baseIntent;
- }
-
@Override
public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
final String key = preference.getKey();
@@ -491,18 +414,6 @@ public class SecuritySettings extends SettingsPreferenceFragment
if (KEY_UNLOCK_SET_OR_CHANGE.equals(key)) {
startFragment(this, "com.android.settings.ChooseLockGeneric$ChooseLockGenericFragment",
SET_OR_CHANGE_LOCK_METHOD_REQUEST, null);
- } else if (KEY_CHOOSE_LOCKSCREEN_WIDGET.equals(key)) {
- int defaultIconId;
- ComponentName clock = new ComponentName(
- "com.google.android.deskclock", "com.android.deskclock.DeskClock");
- try {
- defaultIconId = getActivity().getPackageManager().getActivityInfo(clock, 0).icon;
- } catch (PackageManager.NameNotFoundException e) {
- defaultIconId = 0;
- }
- launchPickActivityIntent(AppWidgetProviderInfo.WIDGET_FEATURES_NONE,
- R.string.widget_default, defaultIconId, clock, EXTRA_DEFAULT_WIDGET,
- REQUEST_PICK_APPWIDGET);
} else if (KEY_BIOMETRIC_WEAK_IMPROVE_MATCHING.equals(key)) {
ChooseLockSettingsHelper helper =
new ChooseLockSettingsHelper(this.getActivity(), this);
@@ -583,48 +494,6 @@ public class SecuritySettings extends SettingsPreferenceFragment
// is called by grabbing the value from lockPatternUtils. We can't set it here
// because mBiometricWeakLiveliness could be null
return;
- } else if (requestCode == REQUEST_PICK_APPWIDGET || requestCode == REQUEST_CREATE_APPWIDGET) {
- int appWidgetId = (data == null) ? -1 : data.getIntExtra(
- AppWidgetManager.EXTRA_APPWIDGET_ID, -1);
- if ((requestCode == REQUEST_PICK_APPWIDGET) &&
- resultCode == Activity.RESULT_OK) {
- AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(getActivity());
- boolean defaultWidget = data.getBooleanExtra(EXTRA_DEFAULT_WIDGET, false);
-
- AppWidgetProviderInfo appWidget = null;
- if (!defaultWidget) {
- appWidget = appWidgetManager.getAppWidgetInfo(appWidgetId);
- }
-
- if (!defaultWidget && appWidget.configure != null) {
- // Launch over to configure widget, if needed
- Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_CONFIGURE);
- intent.setComponent(appWidget.configure);
- intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
-
- startActivityForResultSafely(intent, REQUEST_CREATE_APPWIDGET);
- } else {
- // Otherwise just add it
- if (defaultWidget) {
- // If we selected "none", delete the allocated id
- AppWidgetHost.deleteAppWidgetIdForSystem(appWidgetId);
- data.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
- LockPatternUtils.ID_DEFAULT_STATUS_WIDGET);
- }
- onActivityResult(REQUEST_CREATE_APPWIDGET, Activity.RESULT_OK, data);
- }
- } else if (requestCode == REQUEST_CREATE_APPWIDGET && resultCode == Activity.RESULT_OK) {
- mLockPatternUtils.addAppWidget(appWidgetId, 0);
-
- IBinder b = ServiceManager.getService(Context.WINDOW_SERVICE);
- IWindowManager iWm = IWindowManager.Stub.asInterface(b);
- try {
- iWm.lockNow(null);
- } catch (RemoteException e) {
- }
- } else {
- AppWidgetHost.deleteAppWidgetIdForSystem(appWidgetId);
- }
}
createPreferenceHierarchy();
}