* commit '6df9ce11ca25ed0013c58dae34ac874322bd09fa': New widget picker for keyguard widgets
This commit is contained in:
@@ -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">
|
||||
|
BIN
res/drawable-hdpi/appwidget_item_bg_normal.9.png
Normal file
BIN
res/drawable-hdpi/appwidget_item_bg_normal.9.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 468 B |
BIN
res/drawable-hdpi/appwidget_item_bg_pressed.9.png
Normal file
BIN
res/drawable-hdpi/appwidget_item_bg_pressed.9.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 553 B |
BIN
res/drawable-mdpi/appwidget_item_bg_normal.9.png
Normal file
BIN
res/drawable-mdpi/appwidget_item_bg_normal.9.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 332 B |
BIN
res/drawable-mdpi/appwidget_item_bg_pressed.9.png
Normal file
BIN
res/drawable-mdpi/appwidget_item_bg_pressed.9.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 394 B |
BIN
res/drawable-xhdpi/appwidget_item_bg_normal.9.png
Normal file
BIN
res/drawable-xhdpi/appwidget_item_bg_normal.9.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 591 B |
BIN
res/drawable-xhdpi/appwidget_item_bg_pressed.9.png
Normal file
BIN
res/drawable-xhdpi/appwidget_item_bg_pressed.9.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 737 B |
23
res/drawable/appwidget_item_bg.xml
Normal file
23
res/drawable/appwidget_item_bg.xml
Normal file
@@ -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>
|
35
res/layout/keyguard_appwidget_item.xml
Executable file
35
res/layout/keyguard_appwidget_item.xml
Executable file
@@ -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>
|
27
res/layout/keyguard_appwidget_pick_layout.xml
Normal file
27
res/layout/keyguard_appwidget_pick_layout.xml
Normal file
@@ -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>
|
@@ -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>
|
||||
|
||||
|
@@ -51,12 +51,6 @@
|
||||
android:key="power_button_instantly_locks"
|
||||
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"
|
||||
|
@@ -26,12 +26,6 @@
|
||||
android:summary="@string/unlock_set_unlock_mode_none"
|
||||
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"
|
||||
|
@@ -38,12 +38,6 @@
|
||||
android:key="power_button_instantly_locks"
|
||||
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"
|
||||
|
@@ -42,12 +42,6 @@
|
||||
android:key="power_button_instantly_locks"
|
||||
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"
|
||||
|
@@ -38,12 +38,6 @@
|
||||
android:key="power_button_instantly_locks"
|
||||
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"
|
||||
|
@@ -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;
|
||||
|
182
src/com/android/settings/AppWidgetLoader.java
Normal file
182
src/com/android/settings/AppWidgetLoader.java
Normal file
@@ -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);
|
||||
}
|
||||
}
|
@@ -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,60 +82,60 @@ 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();
|
||||
@Override
|
||||
protected List<PickAdapter.Item> getItems() {
|
||||
mItems = mAppWidgetLoader.getItems(getIntent());
|
||||
return mItems;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
@Override
|
||||
public PickAdapter.Item createItem(Context context, AppWidgetProviderInfo info, Bundle extras) {
|
||||
CharSequence label = info.label;
|
||||
Drawable icon = null;
|
||||
|
||||
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;
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
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 (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;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -147,7 +144,7 @@ public class AppWidgetPickActivity extends ActivityPicker {
|
||||
@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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
579
src/com/android/settings/KeyguardAppWidgetPickActivity.java
Normal file
579
src/com/android/settings/KeyguardAppWidgetPickActivity.java
Normal file
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@@ -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();
|
||||
}
|
||||
|
Reference in New Issue
Block a user