Replacing hotseat icon to an appropriate system app

> During backupi, store the hotseat target app type, based on some predefined
common system apps
> During restore, save this app type in the restore flag, if it is a hotseat app
> During first launcher load, if an app is not being restored, try to replace it
with an appropriate replacement for that type, otherwise delete it.

Bug: 18764649
Change-Id: Ic49e40bd707bd8d7de18bbab8b1e58a0a36426a2
This commit is contained in:
Sunny Goyal 2015-01-15 12:00:14 -08:00
parent 3862e4d88b
commit bb3b02f562
13 changed files with 491 additions and 27 deletions

View File

@ -72,6 +72,17 @@ message Journal {
}
message Favorite {
// Type of the app, this target represents
enum TargetType {
TARGET_NONE = 0;
TARGET_PHONE = 1;
TARGET_MESSENGER = 2;
TARGET_EMAIL = 3;
TARGET_BROWSER = 4;
TARGET_GALLERY = 5;
TARGET_CAMERA = 6;
}
required int64 id = 1;
required int32 itemType = 2;
optional string title = 3;
@ -90,6 +101,7 @@ message Favorite {
optional string iconPackage = 16;
optional string iconResource = 17;
optional bytes icon = 18;
optional TargetType targetType = 19 [default = TARGET_NONE];
}
message Screen {

View File

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2015 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.
-->
<resolve xmlns:launcher="http://schemas.android.com/apk/res-auto/com.android.launcher3" >
<favorite launcher:uri="#Intent;action=android.intent.action.MAIN;category=android.intent.category.APP_BROWSER;end" />
<favorite launcher:uri="http://www.example.com/" />
</resolve>

View File

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2015 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.
-->
<resolve xmlns:launcher="http://schemas.android.com/apk/res-auto/com.android.launcher3" >
<favorite launcher:uri="#Intent;action=android.media.action.STILL_IMAGE_CAMERA;end" />
<favorite launcher:uri="#Intent;action=android.intent.action.CAMERA_BUTTON;end" />
</resolve>

View File

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2015 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.
-->
<resolve xmlns:launcher="http://schemas.android.com/apk/res-auto/com.android.launcher3" >
<favorite launcher:uri="#Intent;action=android.intent.action.MAIN;category=android.intent.category.APP_EMAIL;end" />
<favorite launcher:uri="mailto:" />
</resolve>

View File

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2015 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.
-->
<resolve xmlns:launcher="http://schemas.android.com/apk/res-auto/com.android.launcher3" >
<favorite launcher:uri="#Intent;action=android.intent.action.MAIN;category=android.intent.category.APP_GALLERY;end" />
<favorite launcher:uri="#Intent;type=images/*;end" />
</resolve>

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2015 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.
-->
<resolve xmlns:launcher="http://schemas.android.com/apk/res-auto/com.android.launcher3" >
<favorite launcher:uri="#Intent;action=android.intent.action.MAIN;category=android.intent.category.APP_MESSAGING;end" />
<favorite launcher:uri="sms:" />
<favorite launcher:uri="smsto:" />
<favorite launcher:uri="mms:" />
<favorite launcher:uri="mmsto:" />
</resolve>

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2015 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.
-->
<resolve xmlns:launcher="http://schemas.android.com/apk/res-auto/com.android.launcher3" >
<favorite launcher:uri="#Intent;action=android.intent.action.DIAL;end" />
<favorite launcher:uri="tel:123" />
<favorite launcher:uri="#Intent;action=android.intent.action.CALL_BUTTON;end" />
</resolve>

View File

@ -112,7 +112,7 @@ public class AutoInstallsLayout {
private final Context mContext;
private final AppWidgetHost mAppWidgetHost;
private final LayoutParserCallback mCallback;
protected final LayoutParserCallback mCallback;
protected final PackageManager mPackageManager;
protected final Resources mSourceRes;
@ -122,13 +122,20 @@ public class AutoInstallsLayout {
private final long[] mTemp = new long[2];
private final ContentValues mValues;
private final String mRootTag;
protected final String mRootTag;
protected SQLiteDatabase mDb;
public AutoInstallsLayout(Context context, AppWidgetHost appWidgetHost,
LayoutParserCallback callback, Resources res,
int layoutId, String rootTag) {
this(context, appWidgetHost, callback, res, layoutId, rootTag,
LauncherAppState.getInstance().getDynamicGrid().getDeviceProfile().hotseatAllAppsRank);
}
public AutoInstallsLayout(Context context, AppWidgetHost appWidgetHost,
LayoutParserCallback callback, Resources res,
int layoutId, String rootTag, int hotseatAllAppsRank) {
mContext = context;
mAppWidgetHost = appWidgetHost;
mCallback = callback;
@ -139,8 +146,7 @@ public class AutoInstallsLayout {
mSourceRes = res;
mLayoutId = layoutId;
mHotseatAllAppsRank = LauncherAppState.getInstance()
.getDynamicGrid().getDeviceProfile().hotseatAllAppsRank;
mHotseatAllAppsRank = hotseatAllAppsRank;
}
/**

View File

@ -0,0 +1,152 @@
/*
* Copyright (C) 2008 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.launcher3;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.res.XmlResourceParser;
import android.database.sqlite.SQLiteDatabase;
import android.util.Log;
import com.android.launcher3.AutoInstallsLayout.LayoutParserCallback;
import com.android.launcher3.LauncherSettings.Favorites;
import com.android.launcher3.backup.BackupProtos.Favorite;
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
/**
* A class that parses content values corresponding to some common app types.
*/
public class CommonAppTypeParser implements LayoutParserCallback {
private static final String TAG = "CommonAppTypeParser";
// Including TARGET_NONE
public static final int SUPPORTED_TYPE_COUNT = 7;
private static final int RESTORE_FLAG_BIT_SHIFT = 4;
private final long mItemId;
private final int mResId;
private final Context mContext;
ContentValues parsedValues;
Intent parsedIntent;
String parsedTitle;
public CommonAppTypeParser(long itemId, int itemType, Context context) {
mItemId = itemId;
mContext = context;
mResId = getResourceForItemType(itemType);
}
@Override
public long generateNewItemId() {
return mItemId;
}
@Override
public long insertAndCheck(SQLiteDatabase db, ContentValues values) {
parsedValues = values;
// Remove unwanted values
values.put(Favorites.ICON_TYPE, (Integer) null);
values.put(Favorites.ICON_PACKAGE, (String) null);
values.put(Favorites.ICON_RESOURCE, (String) null);
values.put(Favorites.ICON, (byte[]) null);
return 1;
}
/**
* Tries to find a suitable app to the provided app type.
*/
public boolean findDefaultApp() {
if (mResId == 0) {
return false;
}
parsedIntent = null;
parsedValues = null;
new MyLayoutParser().parseValues();
return (parsedValues != null) && (parsedIntent != null);
}
private class MyLayoutParser extends DefaultLayoutParser {
public MyLayoutParser() {
super(mContext, null, CommonAppTypeParser.this,
mContext.getResources(), mResId, TAG_RESOLVE, 0);
}
@Override
protected long addShortcut(String title, Intent intent, int type) {
if (type == Favorites.ITEM_TYPE_APPLICATION) {
parsedIntent = intent;
parsedTitle = title;
}
return super.addShortcut(title, intent, type);
}
public void parseValues() {
XmlResourceParser parser = mSourceRes.getXml(mLayoutId);
try {
beginDocument(parser, mRootTag);
new ResolveParser().parseAndAdd(parser);
} catch (IOException | XmlPullParserException e) {
Log.e(TAG, "Unable to parse default app info", e);
}
parser.close();
}
}
public static int getResourceForItemType(int type) {
switch (type) {
case Favorite.TARGET_PHONE:
return R.xml.app_target_phone;
case Favorite.TARGET_MESSENGER:
return R.xml.app_target_messenger;
case Favorite.TARGET_EMAIL:
return R.xml.app_target_email;
case Favorite.TARGET_BROWSER:
return R.xml.app_target_browser;
case Favorite.TARGET_GALLERY:
return R.xml.app_target_gallery;
case Favorite.TARGET_CAMERA:
return R.xml.app_target_camera;
default:
return 0;
}
}
public static int encodeItemTypeToFlag(int itemType) {
return itemType << RESTORE_FLAG_BIT_SHIFT;
}
public static int decodeItemTypeFromFlag(int flag) {
return (flag & ShortcutInfo.FLAG_RESTORED_APP_TYPE) >> RESTORE_FLAG_BIT_SHIFT;
}
}

View File

@ -29,16 +29,16 @@ import java.util.List;
public class DefaultLayoutParser extends AutoInstallsLayout {
private static final String TAG = "DefaultLayoutParser";
private static final String TAG_RESOLVE = "resolve";
protected static final String TAG_RESOLVE = "resolve";
private static final String TAG_FAVORITES = "favorites";
private static final String TAG_FAVORITE = "favorite";
protected static final String TAG_FAVORITE = "favorite";
private static final String TAG_APPWIDGET = "appwidget";
private static final String TAG_SHORTCUT = "shortcut";
private static final String TAG_FOLDER = "folder";
private static final String TAG_PARTNER_FOLDER = "partner-folder";
private static final String TAG_INCLUDE = "include";
private static final String ATTR_URI = "uri";
protected static final String ATTR_URI = "uri";
private static final String ATTR_WORKSPACE = "workspace";
private static final String ATTR_CONTAINER = "container";
private static final String ATTR_SCREEN = "screen";
@ -47,7 +47,12 @@ public class DefaultLayoutParser extends AutoInstallsLayout {
public DefaultLayoutParser(Context context, AppWidgetHost appWidgetHost,
LayoutParserCallback callback, Resources sourceRes, int layoutId) {
super(context, appWidgetHost, callback, sourceRes, layoutId, TAG_FAVORITES);
Log.e(TAG, "Default layout parser initialized");
}
public DefaultLayoutParser(Context context, AppWidgetHost appWidgetHost,
LayoutParserCallback callback, Resources sourceRes, int layoutId, String rootTag,
int hotseatAllAppsRank) {
super(context, appWidgetHost, callback, sourceRes, layoutId, rootTag, hotseatAllAppsRank);
}
@Override
@ -218,7 +223,7 @@ public class DefaultLayoutParser extends AutoInstallsLayout {
/**
* Contains a list of <favorite> nodes, and accepts the first successfully parsed node.
*/
private class ResolveParser implements TagParser {
protected class ResolveParser implements TagParser {
private final AppShortcutWithUriParser mChildParser = new AppShortcutWithUriParser();

View File

@ -19,13 +19,16 @@ import android.app.backup.BackupDataInputStream;
import android.app.backup.BackupDataOutput;
import android.app.backup.BackupHelper;
import android.app.backup.BackupManager;
import android.appwidget.AppWidgetProviderInfo;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
import android.content.res.XmlResourceParser;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
@ -51,6 +54,9 @@ import com.android.launcher3.compat.UserManagerCompat;
import com.google.protobuf.nano.InvalidProtocolBufferNanoException;
import com.google.protobuf.nano.MessageNano;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
@ -58,7 +64,6 @@ import java.io.IOException;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.zip.CRC32;
@ -138,6 +143,7 @@ public class LauncherBackupHelper implements BackupHelper {
private final Context mContext;
private final HashSet<String> mExistingKeys;
private final ArrayList<Key> mKeys;
private final ItemTypeMatcher[] mItemTypeMatchers;
private IconCache mIconCache;
private BackupManager mBackupManager;
@ -154,6 +160,7 @@ public class LauncherBackupHelper implements BackupHelper {
mExistingKeys = new HashSet<String>();
mKeys = new ArrayList<Key>();
restoreSuccessful = true;
mItemTypeMatchers = new ItemTypeMatcher[CommonAppTypeParser.SUPPORTED_TYPE_COUNT];
}
private void dataChanged() {
@ -753,6 +760,17 @@ public class LauncherBackupHelper implements BackupHelper {
return checksum.getValue();
}
/**
* @return true if its an hotseat item, that can be replaced during restore.
* TODO: Extend check for folders in hotseat.
*/
private boolean isReplaceableHotseatItem(Favorite favorite) {
return favorite.container == Favorites.CONTAINER_HOTSEAT
&& favorite.intent != null
&& (favorite.itemType == Favorites.ITEM_TYPE_APPLICATION
|| favorite.itemType == Favorites.ITEM_TYPE_SHORTCUT);
}
/** Serialize a Favorite for persistence, including a checksum wrapper. */
private Favorite packFavorite(Cursor c) {
Favorite favorite = new Favorite();
@ -785,9 +803,10 @@ public class LauncherBackupHelper implements BackupHelper {
favorite.title = title;
}
String intentDescription = c.getString(INTENT_INDEX);
Intent intent = null;
if (!TextUtils.isEmpty(intentDescription)) {
try {
Intent intent = Intent.parseUri(intentDescription, 0);
intent = Intent.parseUri(intentDescription, 0);
intent.removeExtra(ItemInfo.EXTRA_PROFILE);
favorite.intent = intent.toUri(0);
} catch (URISyntaxException e) {
@ -803,6 +822,31 @@ public class LauncherBackupHelper implements BackupHelper {
}
}
if (isReplaceableHotseatItem(favorite)) {
if (intent != null && intent.getComponent() != null) {
PackageManager pm = mContext.getPackageManager();
ActivityInfo activity = null;;
try {
activity = pm.getActivityInfo(intent.getComponent(), 0);
} catch (NameNotFoundException e) {
Log.e(TAG, "Target not found", e);
}
if (activity == null) {
return favorite;
}
for (int i = 0; i < mItemTypeMatchers.length; i++) {
if (mItemTypeMatchers[i] == null) {
mItemTypeMatchers[i] = new ItemTypeMatcher(
CommonAppTypeParser.getResourceForItemType(i));
}
if (mItemTypeMatchers[i].matches(activity, pm)) {
favorite.targetType = i;
break;
}
}
}
}
return favorite;
}
@ -810,6 +854,7 @@ public class LauncherBackupHelper implements BackupHelper {
private ContentValues unpackFavorite(byte[] buffer, int dataSize)
throws IOException {
Favorite favorite = unpackProto(new Favorite(), buffer, dataSize);
ContentValues values = new ContentValues();
values.put(Favorites._ID, favorite.id);
values.put(Favorites.SCREEN, favorite.screen);
@ -860,8 +905,17 @@ public class LauncherBackupHelper implements BackupHelper {
throw new InvalidBackupException("Widget not in screen bounds, aborting restore");
}
} else {
// Let LauncherModel know we've been here.
values.put(LauncherSettings.Favorites.RESTORED, 1);
// Check if it is an hotseat item, that can be replaced.
if (isReplaceableHotseatItem(favorite)
&& favorite.targetType != Favorite.TARGET_NONE
&& favorite.targetType < CommonAppTypeParser.SUPPORTED_TYPE_COUNT) {
Log.e(TAG, "Added item type flag");
values.put(LauncherSettings.Favorites.RESTORED,
1 | CommonAppTypeParser.encodeItemTypeToFlag(favorite.targetType));
} else {
// Let LauncherModel know we've been here.
values.put(LauncherSettings.Favorites.RESTORED, 1);
}
// Verify placement
if (favorite.container == Favorites.CONTAINER_HOTSEAT) {
@ -1128,6 +1182,9 @@ public class LauncherBackupHelper implements BackupHelper {
}
private class InvalidBackupException extends IOException {
private static final long serialVersionUID = 8931456637211665082L;
private InvalidBackupException(Throwable cause) {
super(cause);
}
@ -1136,4 +1193,54 @@ public class LauncherBackupHelper implements BackupHelper {
super(reason);
}
}
/**
* A class to check if an activity can handle one of the intents from a list of
* predefined intents.
*/
private class ItemTypeMatcher {
private final ArrayList<Intent> mIntents;
ItemTypeMatcher(int xml_res) {
mIntents = xml_res == 0 ? new ArrayList<Intent>() : parseIntents(xml_res);
}
private ArrayList<Intent> parseIntents(int xml_res) {
ArrayList<Intent> intents = new ArrayList<Intent>();
XmlResourceParser parser = mContext.getResources().getXml(xml_res);
try {
DefaultLayoutParser.beginDocument(parser, DefaultLayoutParser.TAG_RESOLVE);
final int depth = parser.getDepth();
int type;
while (((type = parser.next()) != XmlPullParser.END_TAG ||
parser.getDepth() > depth) && type != XmlPullParser.END_DOCUMENT) {
if (type != XmlPullParser.START_TAG) {
continue;
} else if (DefaultLayoutParser.TAG_FAVORITE.equals(parser.getName())) {
final String uri = DefaultLayoutParser.getAttributeValue(
parser, DefaultLayoutParser.ATTR_URI);
intents.add(Intent.parseUri(uri, 0));
}
}
} catch (URISyntaxException | XmlPullParserException | IOException e) {
Log.e(TAG, "Unable to parse " + xml_res, e);
} finally {
parser.close();
}
return intents;
}
public boolean matches(ActivityInfo activity, PackageManager pm) {
for (Intent intent : mIntents) {
intent.setPackage(activity.packageName);
ResolveInfo info = pm.resolveActivity(intent, 0);
if (info != null && (info.activityInfo.name.equals(activity.name)
|| info.activityInfo.name.equals(activity.targetActivity))) {
return true;
}
}
return false;
}
}
}

View File

@ -1955,6 +1955,7 @@ public class LauncherModel extends BroadcastReceiver
user = mUserManager.getUserForSerialNumber(serialNumber);
int promiseType = c.getInt(restoredIndex);
int disabledState = 0;
boolean itemReplaced = false;
if (user == null) {
// User has been deleted remove the item.
itemsToRemove.add(id);
@ -1986,9 +1987,7 @@ public class LauncherModel extends BroadcastReceiver
ContentValues values = new ContentValues();
values.put(LauncherSettings.Favorites.INTENT,
intent.toUri(0));
String where = BaseColumns._ID + "= ?";
String[] args = {Long.toString(id)};
contentResolver.update(contentUri, values, where, args);
updateItem(id, values);
}
}
@ -2018,10 +2017,27 @@ public class LauncherModel extends BroadcastReceiver
ContentValues values = new ContentValues();
values.put(LauncherSettings.Favorites.RESTORED,
promiseType);
String where = BaseColumns._ID + "= ?";
String[] args = {Long.toString(id)};
contentResolver.update(contentUri, values, where, args);
updateItem(id, values);
} else if ((promiseType & ShortcutInfo.FLAG_RESTORED_APP_TYPE) != 0) {
// This is a common app. Try to replace this.
int appType = CommonAppTypeParser.decodeItemTypeFromFlag(promiseType);
CommonAppTypeParser parser = new CommonAppTypeParser(id, appType, context);
if (parser.findDefaultApp()) {
// Default app found. Replace it.
intent = parser.parsedIntent;
cn = intent.getComponent();
ContentValues values = parser.parsedValues;
values.put(LauncherSettings.Favorites.RESTORED, 0);
updateItem(id, values);
restored = false;
itemReplaced = true;
} else if (REMOVE_UNRESTORED_ICONS) {
Launcher.addDumpLog(TAG,
"Unrestored package removed: " + cn, true);
itemsToRemove.add(id);
continue;
}
} else if (REMOVE_UNRESTORED_ICONS) {
Launcher.addDumpLog(TAG,
"Unrestored package removed: " + cn, true);
@ -2067,7 +2083,16 @@ public class LauncherModel extends BroadcastReceiver
continue;
}
if (restored) {
if (itemReplaced) {
if (user.equals(UserHandleCompat.myUserHandle())) {
info = getShortcutInfo(manager, intent, user, context, null,
iconIndex, titleIndex, mLabelCache, false);
} else {
// Don't replace items for other profiles.
itemsToRemove.add(id);
continue;
}
} else if (restored) {
if (user.equals(UserHandleCompat.myUserHandle())) {
Launcher.addDumpLog(TAG,
"constructing info for partially restored package",
@ -2301,9 +2326,7 @@ public class LauncherModel extends BroadcastReceiver
providerName);
values.put(LauncherSettings.Favorites.RESTORED,
appWidgetInfo.restoreStatus);
String where = BaseColumns._ID + "= ?";
String[] args = {Long.toString(id)};
contentResolver.update(contentUri, values, where, args);
updateItem(id, values);
}
}
sBgItemsIdMap.put(appWidgetInfo.id, appWidgetInfo);
@ -2455,6 +2478,17 @@ public class LauncherModel extends BroadcastReceiver
return loadedOldDb;
}
/**
* Partially updates the item without any notification. Must be called on the worker thread.
*/
private void updateItem(long itemId, ContentValues update) {
mContext.getContentResolver().update(
LauncherSettings.Favorites.CONTENT_URI_NO_NOTIFICATION,
update,
BaseColumns._ID + "= ?",
new String[]{Long.toString(itemId)});
}
/** Filters the set of items who are directly or indirectly (via another container) on the
* specified screen. */
private void filterCurrentWorkspaceItems(long currentScreenId,

View File

@ -46,18 +46,24 @@ public class ShortcutInfo extends ItemInfo {
* be present along with {@link #FLAG_RESTORED_ICON}, and is set during default layout
* parsing.
*/
public static final int FLAG_AUTOINTALL_ICON = 2;
public static final int FLAG_AUTOINTALL_ICON = 2; //0B10;
/**
* The icon is being installed. If {@link FLAG_RESTORED_ICON} or {@link FLAG_AUTOINTALL_ICON}
* is set, then the icon is either being installed or is in a broken state.
*/
public static final int FLAG_INSTALL_SESSION_ACTIVE = 4;
public static final int FLAG_INSTALL_SESSION_ACTIVE = 4; // 0B100;
/**
* Indicates that the widget restore has started.
*/
public static final int FLAG_RESTORE_STARTED = 8;
public static final int FLAG_RESTORE_STARTED = 8; //0B1000;
/**
* Indicates if it represents a common type mentioned in {@link CommonAppTypeParser}.
* Upto 15 different types supported.
*/
public static final int FLAG_RESTORED_APP_TYPE = 0B0011110000;
/**
* The intent used to start the application.