Snap for 5124112 from ee817568b6 to qt-release
Change-Id: I893897309f661f082b92f3fff3c52e8ba18c0769
This commit is contained in:
@@ -36,16 +36,14 @@
|
||||
android:restoreAnyVersion="true"
|
||||
android:supportsRtl="true" >
|
||||
|
||||
<!-- Activity for handling PinItemRequest. Only supports shortcuts -->
|
||||
<!-- Activity for handling PinItemRequest is disabled on Android Go. -->
|
||||
<activity android:name="com.android.launcher3.dragndrop.AddItemActivity"
|
||||
android:theme="@android:style/Theme.DeviceDefault.Light.Dialog.Alert"
|
||||
android:excludeFromRecents="true"
|
||||
android:autoRemoveFromRecents="true"
|
||||
android:label="@string/action_add_to_workspace"
|
||||
android:enabled="false"
|
||||
tools:node="replace" >
|
||||
<intent-filter>
|
||||
<action android:name="android.content.pm.action.CONFIRM_PIN_SHORTCUT" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
</application>
|
||||
|
||||
@@ -1,66 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2017 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.
|
||||
-->
|
||||
<merge xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="@dimen/widget_preview_label_vertical_padding"
|
||||
android:paddingBottom="@dimen/widget_preview_label_vertical_padding"
|
||||
android:paddingLeft="@dimen/widget_preview_label_horizontal_padding"
|
||||
android:paddingRight="@dimen/widget_preview_label_horizontal_padding"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<!-- The name of the widget. -->
|
||||
<TextView
|
||||
android:id="@+id/widget_name"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:ellipsize="end"
|
||||
android:fadingEdge="horizontal"
|
||||
android:fontFamily="sans-serif-condensed"
|
||||
android:gravity="center"
|
||||
android:singleLine="true"
|
||||
android:maxLines="1"
|
||||
android:textColor="?android:attr/textColorSecondary"
|
||||
android:textSize="14sp" />
|
||||
|
||||
<!-- The original dimensions of the widget (can't be the same text as above due to different
|
||||
style. -->
|
||||
<TextView
|
||||
android:id="@+id/widget_dims"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="5dp"
|
||||
android:layout_marginLeft="5dp"
|
||||
android:visibility="gone"
|
||||
android:textColor="?android:attr/textColorSecondary"
|
||||
android:textSize="14sp"
|
||||
android:fontFamily="sans-serif-condensed"
|
||||
android:alpha="0.8" />
|
||||
</LinearLayout>
|
||||
|
||||
<!-- The image of the widget. This view does not support padding. Any placement adjustment
|
||||
should be done using margins. -->
|
||||
<com.android.launcher3.widget.WidgetImageView
|
||||
android:id="@+id/widget_preview"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1" />
|
||||
</merge>
|
||||
@@ -37,6 +37,11 @@ android {
|
||||
tasks.withType(JavaCompile) {
|
||||
options.compilerArgs << "-Xlint:unchecked" << "-Xlint:deprecation"
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
+2
-4
@@ -13,7 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.launcher3.graphics;
|
||||
package com.android.launcher3.icons;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.graphics.Bitmap;
|
||||
@@ -21,14 +21,12 @@ import android.graphics.Canvas;
|
||||
import android.graphics.Picture;
|
||||
import android.os.Build;
|
||||
|
||||
import com.android.launcher3.Utilities;
|
||||
|
||||
/**
|
||||
* Interface representing a bitmap draw operation.
|
||||
*/
|
||||
public interface BitmapRenderer {
|
||||
|
||||
boolean USE_HARDWARE_BITMAP = Utilities.ATLEAST_P;
|
||||
boolean USE_HARDWARE_BITMAP = Build.VERSION.SDK_INT >= Build.VERSION_CODES.P;
|
||||
|
||||
static Bitmap createSoftwareBitmap(int width, int height, BitmapRenderer renderer) {
|
||||
Bitmap result = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
|
||||
@@ -15,10 +15,18 @@
|
||||
*/
|
||||
package com.android.launcher3.icons;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import androidx.annotation.ColorInt;
|
||||
|
||||
public class GraphicsUtils {
|
||||
|
||||
private static final String TAG = "GraphicsUtils";
|
||||
|
||||
/**
|
||||
* Set the alpha component of {@code color} to be {@code alpha}. Unlike the support lib version,
|
||||
* it bounds the alpha in valid range instead of throwing an exception to allow for safer
|
||||
@@ -33,4 +41,23 @@ public class GraphicsUtils {
|
||||
}
|
||||
return (color & 0x00ffffff) | (alpha << 24);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compresses the bitmap to a byte array for serialization.
|
||||
*/
|
||||
public static byte[] flattenBitmap(Bitmap bitmap) {
|
||||
// Try go guesstimate how much space the icon will take when serialized
|
||||
// to avoid unnecessary allocations/copies during the write (4 bytes per pixel).
|
||||
int size = bitmap.getWidth() * bitmap.getHeight() * 4;
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream(size);
|
||||
try {
|
||||
bitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
|
||||
out.flush();
|
||||
out.close();
|
||||
return out.toByteArray();
|
||||
} catch (IOException e) {
|
||||
Log.w(TAG, "Could not write bitmap");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+3
-2
@@ -29,8 +29,9 @@ public class ComponentKey {
|
||||
private final int mHashCode;
|
||||
|
||||
public ComponentKey(ComponentName componentName, UserHandle user) {
|
||||
Preconditions.assertNotNull(componentName);
|
||||
Preconditions.assertNotNull(user);
|
||||
if (componentName == null || user == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
this.componentName = componentName;
|
||||
this.user = user;
|
||||
mHashCode = Arrays.hashCode(new Object[] {componentName, user});
|
||||
+4
-2
@@ -18,8 +18,6 @@ package com.android.launcher3.util;
|
||||
|
||||
import static android.database.sqlite.SQLiteDatabase.NO_LOCALIZED_COLLATORS;
|
||||
|
||||
import static com.android.launcher3.Utilities.ATLEAST_P;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.ContextWrapper;
|
||||
import android.database.DatabaseErrorHandler;
|
||||
@@ -27,6 +25,7 @@ import android.database.sqlite.SQLiteDatabase;
|
||||
import android.database.sqlite.SQLiteDatabase.CursorFactory;
|
||||
import android.database.sqlite.SQLiteDatabase.OpenParams;
|
||||
import android.database.sqlite.SQLiteOpenHelper;
|
||||
import android.os.Build;
|
||||
|
||||
/**
|
||||
* Extension of {@link SQLiteOpenHelper} which avoids creating default locale table by
|
||||
@@ -34,6 +33,9 @@ import android.database.sqlite.SQLiteOpenHelper;
|
||||
*/
|
||||
public abstract class NoLocaleSQLiteHelper extends SQLiteOpenHelper {
|
||||
|
||||
private static final boolean ATLEAST_P =
|
||||
Build.VERSION.SDK_INT >= Build.VERSION_CODES.P;
|
||||
|
||||
public NoLocaleSQLiteHelper(Context context, String name, int version) {
|
||||
super(ATLEAST_P ? context : new NoLocalContext(context), name, null, version);
|
||||
if (ATLEAST_P) {
|
||||
+2
-6
@@ -9,9 +9,6 @@ import android.database.sqlite.SQLiteFullException;
|
||||
import android.database.sqlite.SQLiteOpenHelper;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.config.FeatureFlags;
|
||||
|
||||
/**
|
||||
* An extension of {@link SQLiteOpenHelper} with utility methods for a single table cache DB.
|
||||
* Any exception during write operations are ignored, and any version change causes a DB reset.
|
||||
@@ -19,8 +16,7 @@ import com.android.launcher3.config.FeatureFlags;
|
||||
public abstract class SQLiteCacheHelper {
|
||||
private static final String TAG = "SQLiteCacheHelper";
|
||||
|
||||
private static final boolean NO_ICON_CACHE = FeatureFlags.IS_DOGFOOD_BUILD &&
|
||||
Utilities.isPropertyEnabled(LogConfig.MEMORY_ONLY_ICON_CACHE);
|
||||
private static final boolean IN_MEMORY_CACHE = false;
|
||||
|
||||
private final String mTableName;
|
||||
private final MySQLiteOpenHelper mOpenHelper;
|
||||
@@ -28,7 +24,7 @@ public abstract class SQLiteCacheHelper {
|
||||
private boolean mIgnoreWrites;
|
||||
|
||||
public SQLiteCacheHelper(Context context, String name, int version, String tableName) {
|
||||
if (NO_ICON_CACHE) {
|
||||
if (IN_MEMORY_CACHE) {
|
||||
name = null;
|
||||
}
|
||||
mTableName = tableName;
|
||||
+1
-1
@@ -24,7 +24,7 @@
|
||||
-keep class androidx.recyclerview.widget.RecyclerView { *; }
|
||||
|
||||
# Preference fragments
|
||||
-keep class ** extends android.preference.PreferenceFragment {
|
||||
-keep class ** extends android.app.Fragment {
|
||||
public <init>(...);
|
||||
}
|
||||
|
||||
|
||||
@@ -462,7 +462,7 @@ public class TaskView extends FrameLayout implements PageCallbacks {
|
||||
}
|
||||
|
||||
if (action == R.string.accessibility_app_usage_settings) {
|
||||
openAppUsageSettings();
|
||||
openAppUsageSettings(this);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -484,14 +484,16 @@ public class TaskView extends FrameLayout implements PageCallbacks {
|
||||
return super.performAccessibilityAction(action, arguments);
|
||||
}
|
||||
|
||||
private void openAppUsageSettings() {
|
||||
private void openAppUsageSettings(View view) {
|
||||
final Intent intent = new Intent(SEE_TIME_IN_APP_TEMPLATE)
|
||||
.putExtra(Intent.EXTRA_PACKAGE_NAME,
|
||||
mTask.getTopComponent().getPackageName()).addFlags(
|
||||
Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
|
||||
try {
|
||||
final Launcher launcher = Launcher.getLauncher(getContext());
|
||||
launcher.startActivity(intent);
|
||||
final ActivityOptions options = ActivityOptions.makeScaleUpAnimation(view, 0, 0,
|
||||
view.getWidth(), view.getHeight());
|
||||
launcher.startActivity(intent, options.toBundle());
|
||||
launcher.getUserEventDispatcher().logActionOnControl(LauncherLogProto.Action.Touch.TAP,
|
||||
LauncherLogProto.ControlType.APP_USAGE_SETTINGS, this);
|
||||
} catch (ActivityNotFoundException e) {
|
||||
|
||||
+44
-1
@@ -30,7 +30,50 @@
|
||||
layout="@layout/all_apps_rv_layout"
|
||||
android:visibility="gone" />
|
||||
|
||||
<include layout="@layout/all_apps_floating_header" />
|
||||
<com.android.launcher3.allapps.FloatingHeaderView
|
||||
android:id="@+id/all_apps_header"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/search_container_all_apps"
|
||||
android:clipToPadding="false"
|
||||
android:paddingTop="@dimen/all_apps_header_top_padding"
|
||||
android:orientation="vertical" >
|
||||
|
||||
<include layout="@layout/floating_header_content" />
|
||||
|
||||
<com.android.launcher3.allapps.PersonalWorkSlidingTabStrip
|
||||
android:id="@+id/tabs"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/all_apps_header_tab_height"
|
||||
android:layout_marginLeft="@dimen/all_apps_tabs_side_padding"
|
||||
android:layout_marginRight="@dimen/all_apps_tabs_side_padding"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<Button
|
||||
android:id="@+id/tab_personal"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:fontFamily="sans-serif-medium"
|
||||
android:text="@string/all_apps_personal_tab"
|
||||
android:textAllCaps="true"
|
||||
android:textColor="@color/all_apps_tab_text"
|
||||
android:textSize="14sp" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/tab_work"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:fontFamily="sans-serif-medium"
|
||||
android:text="@string/all_apps_work_tab"
|
||||
android:textAllCaps="true"
|
||||
android:textColor="@color/all_apps_tab_text"
|
||||
android:textSize="14sp" />
|
||||
</com.android.launcher3.allapps.PersonalWorkSlidingTabStrip>
|
||||
</com.android.launcher3.allapps.FloatingHeaderView>
|
||||
|
||||
<include
|
||||
android:id="@id/search_container_all_apps"
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2018 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.
|
||||
-->
|
||||
<com.android.launcher3.allapps.FloatingHeaderView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/all_apps_header"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/search_container_all_apps"
|
||||
android:clipToPadding="false"
|
||||
android:paddingTop="@dimen/all_apps_header_top_padding"
|
||||
android:orientation="vertical" >
|
||||
|
||||
<com.android.launcher3.allapps.PersonalWorkSlidingTabStrip
|
||||
android:id="@+id/tabs"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/all_apps_header_tab_height"
|
||||
android:layout_marginLeft="@dimen/all_apps_tabs_side_padding"
|
||||
android:layout_marginRight="@dimen/all_apps_tabs_side_padding"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<Button
|
||||
android:id="@+id/tab_personal"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:fontFamily="sans-serif-medium"
|
||||
android:text="@string/all_apps_personal_tab"
|
||||
android:textAllCaps="true"
|
||||
android:textColor="@color/all_apps_tab_text"
|
||||
android:textSize="14sp" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/tab_work"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:fontFamily="sans-serif-medium"
|
||||
android:text="@string/all_apps_work_tab"
|
||||
android:textAllCaps="true"
|
||||
android:textColor="@color/all_apps_tab_text"
|
||||
android:textSize="14sp" />
|
||||
</com.android.launcher3.allapps.PersonalWorkSlidingTabStrip>
|
||||
</com.android.launcher3.allapps.FloatingHeaderView>
|
||||
@@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2018 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.
|
||||
-->
|
||||
<merge />
|
||||
@@ -39,6 +39,7 @@ import android.util.Patterns;
|
||||
|
||||
import com.android.launcher3.LauncherProvider.SqlArguments;
|
||||
import com.android.launcher3.LauncherSettings.Favorites;
|
||||
import com.android.launcher3.icons.GraphicsUtils;
|
||||
import com.android.launcher3.icons.LauncherIcons;
|
||||
import com.android.launcher3.util.IntArray;
|
||||
import com.android.launcher3.util.Thunk;
|
||||
@@ -47,7 +48,6 @@ import org.xmlpull.v1.XmlPullParser;
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
@@ -436,7 +436,7 @@ public class AutoInstallsLayout {
|
||||
|
||||
// Auto installs should always support the current platform version.
|
||||
LauncherIcons li = LauncherIcons.obtain(mContext);
|
||||
mValues.put(LauncherSettings.Favorites.ICON, Utilities.flattenBitmap(
|
||||
mValues.put(LauncherSettings.Favorites.ICON, GraphicsUtils.flattenBitmap(
|
||||
li.createBadgedIconBitmap(icon, Process.myUserHandle(), VERSION.SDK_INT).icon));
|
||||
li.recycle();
|
||||
|
||||
|
||||
@@ -41,6 +41,7 @@ import android.util.Pair;
|
||||
import com.android.launcher3.compat.LauncherAppsCompat;
|
||||
import com.android.launcher3.compat.UserManagerCompat;
|
||||
import com.android.launcher3.icons.BitmapInfo;
|
||||
import com.android.launcher3.icons.GraphicsUtils;
|
||||
import com.android.launcher3.icons.LauncherIcons;
|
||||
import com.android.launcher3.shortcuts.DeepShortcutManager;
|
||||
import com.android.launcher3.shortcuts.ShortcutInfoCompat;
|
||||
@@ -457,7 +458,7 @@ public class InstallShortcutReceiver extends BroadcastReceiver {
|
||||
.key(LAUNCH_INTENT_KEY).value(launchIntent.toUri(0))
|
||||
.key(NAME_KEY).value(name);
|
||||
if (icon != null) {
|
||||
byte[] iconByteArray = Utilities.flattenBitmap(icon);
|
||||
byte[] iconByteArray = GraphicsUtils.flattenBitmap(icon);
|
||||
json = json.key(ICON_KEY).value(
|
||||
Base64.encodeToString(
|
||||
iconByteArray, 0, iconByteArray.length, Base64.DEFAULT));
|
||||
|
||||
@@ -356,25 +356,6 @@ public final class Utilities {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compresses the bitmap to a byte array for serialization.
|
||||
*/
|
||||
public static byte[] flattenBitmap(Bitmap bitmap) {
|
||||
// Try go guesstimate how much space the icon will take when serialized
|
||||
// to avoid unnecessary allocations/copies during the write.
|
||||
int size = bitmap.getWidth() * bitmap.getHeight() * 4;
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream(size);
|
||||
try {
|
||||
bitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
|
||||
out.flush();
|
||||
out.close();
|
||||
return out.toByteArray();
|
||||
} catch (IOException e) {
|
||||
Log.w(TAG, "Could not write bitmap");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Trims the string, removing all whitespace at the beginning and end of the string.
|
||||
* Non-breaking whitespaces are also removed.
|
||||
|
||||
@@ -31,6 +31,7 @@ import android.util.LongSparseArray;
|
||||
import com.android.launcher3.compat.AppWidgetManagerCompat;
|
||||
import com.android.launcher3.compat.ShortcutConfigActivityInfo;
|
||||
import com.android.launcher3.compat.UserManagerCompat;
|
||||
import com.android.launcher3.icons.GraphicsUtils;
|
||||
import com.android.launcher3.icons.LauncherIcons;
|
||||
import com.android.launcher3.icons.ShadowGenerator;
|
||||
import com.android.launcher3.icons.IconCache;
|
||||
@@ -149,7 +150,7 @@ public class WidgetPreviewLoader {
|
||||
values.put(CacheDb.COLUMN_PACKAGE, key.componentName.getPackageName());
|
||||
values.put(CacheDb.COLUMN_VERSION, versions[0]);
|
||||
values.put(CacheDb.COLUMN_LAST_UPDATED, versions[1]);
|
||||
values.put(CacheDb.COLUMN_PREVIEW_BITMAP, Utilities.flattenBitmap(preview));
|
||||
values.put(CacheDb.COLUMN_PREVIEW_BITMAP, GraphicsUtils.flattenBitmap(preview));
|
||||
mDb.insertOrReplace(values);
|
||||
}
|
||||
|
||||
|
||||
@@ -1625,7 +1625,7 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
|
||||
mDragViewVisualCenter = d.getVisualCenter(mDragViewVisualCenter);
|
||||
|
||||
// We want the point to be mapped to the dragTarget.
|
||||
mapPointFromDropLayout(mLauncher.getHotseat(), mDragViewVisualCenter);
|
||||
mapPointFromDropLayout(dropTargetLayout, mDragViewVisualCenter);
|
||||
|
||||
int spanX;
|
||||
int spanY;
|
||||
@@ -1827,7 +1827,7 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
|
||||
|
||||
// We want the point to be mapped to the dragTarget.
|
||||
if (dropTargetLayout != null) {
|
||||
mapPointFromDropLayout(mLauncher.getHotseat(), mDragViewVisualCenter);
|
||||
mapPointFromDropLayout(dropTargetLayout, mDragViewVisualCenter);
|
||||
}
|
||||
|
||||
boolean droppedOnOriginalCell = false;
|
||||
@@ -2255,7 +2255,7 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
|
||||
// Handle the drag over
|
||||
if (mDragTargetLayout != null) {
|
||||
// We want the point to be mapped to the dragTarget.
|
||||
mapPointFromDropLayout(mLauncher.getHotseat(), mDragViewVisualCenter);
|
||||
mapPointFromDropLayout(mDragTargetLayout, mDragViewVisualCenter);
|
||||
|
||||
int minSpanX = item.spanX;
|
||||
int minSpanY = item.spanY;
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (C) 2018 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.allapps;
|
||||
|
||||
import android.graphics.Rect;
|
||||
import android.view.animation.Interpolator;
|
||||
|
||||
import com.android.launcher3.DeviceProfile;
|
||||
import com.android.launcher3.anim.PropertySetter;
|
||||
|
||||
/**
|
||||
* A abstract representation of a row in all-apps view
|
||||
*/
|
||||
public interface FloatingHeaderRow {
|
||||
|
||||
FloatingHeaderRow[] NO_ROWS = new FloatingHeaderRow[0];
|
||||
|
||||
void setup(FloatingHeaderView parent, FloatingHeaderRow[] allRows, boolean tabsHidden);
|
||||
|
||||
void setInsets(Rect insets, DeviceProfile grid);
|
||||
|
||||
int getExpectedHeight();
|
||||
|
||||
/**
|
||||
* Returns true if the row should draw based on its current position and layout.
|
||||
*/
|
||||
boolean shouldDraw();
|
||||
|
||||
/**
|
||||
* Returns true if the view has anything worth drawing. This is different than
|
||||
* {@link #shouldDraw()} as this is called earlier in the layout to determine the view
|
||||
* position.
|
||||
*/
|
||||
boolean hasVisibleContent();
|
||||
|
||||
void setContentVisibility(boolean hasHeaderExtra, boolean hasContent,
|
||||
PropertySetter setter, Interpolator fadeInterpolator);
|
||||
|
||||
/**
|
||||
* Scrolls the content vertically.
|
||||
*/
|
||||
void setVerticalScroll(int scroll, boolean isScrolledOut);
|
||||
|
||||
Class<? extends FloatingHeaderRow> getTypeClass();
|
||||
}
|
||||
@@ -19,28 +19,34 @@ import android.animation.ValueAnimator;
|
||||
import android.content.Context;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.Rect;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.animation.Interpolator;
|
||||
import android.widget.LinearLayout;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.android.launcher3.DeviceProfile;
|
||||
import com.android.launcher3.Insettable;
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.anim.PropertySetter;
|
||||
import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
|
||||
import com.android.systemui.plugins.AllAppsRow;
|
||||
import com.android.systemui.plugins.AllAppsRow.OnHeightUpdatedListener;
|
||||
import com.android.systemui.plugins.PluginListener;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
public class FloatingHeaderView extends LinearLayout implements
|
||||
ValueAnimator.AnimatorUpdateListener, PluginListener<AllAppsRow> {
|
||||
ValueAnimator.AnimatorUpdateListener, PluginListener<AllAppsRow>, Insettable,
|
||||
OnHeightUpdatedListener {
|
||||
|
||||
private final Rect mClip = new Rect(0, 0, Integer.MAX_VALUE, Integer.MAX_VALUE);
|
||||
private final ValueAnimator mAnimator = ValueAnimator.ofInt(0, 0);
|
||||
@@ -62,17 +68,18 @@ public class FloatingHeaderView extends LinearLayout implements
|
||||
|
||||
int current = -mCurrentRV.getCurrentScrollY();
|
||||
moved(current);
|
||||
apply();
|
||||
applyVerticalMove();
|
||||
}
|
||||
};
|
||||
|
||||
private final int mHeaderTopPadding;
|
||||
|
||||
protected final Map<AllAppsRow, PluginHeaderRow> mPluginRows = new ArrayMap<>();
|
||||
|
||||
protected ViewGroup mTabLayout;
|
||||
private AllAppsRecyclerView mMainRV;
|
||||
private AllAppsRecyclerView mWorkRV;
|
||||
private AllAppsRecyclerView mCurrentRV;
|
||||
protected final Map<AllAppsRow, View> mPluginRows;
|
||||
// Contains just the values of the above map so we can iterate without extracting a new list.
|
||||
protected final List<View> mPluginRowViews;
|
||||
private ViewGroup mParent;
|
||||
private boolean mHeaderCollapsed;
|
||||
private int mSnappedScrolledY;
|
||||
@@ -85,20 +92,42 @@ public class FloatingHeaderView extends LinearLayout implements
|
||||
protected int mMaxTranslation;
|
||||
private boolean mMainRVActive = true;
|
||||
|
||||
private boolean mCollapsed = false;
|
||||
|
||||
// This is initialized once during inflation and stays constant after that. Fixed views
|
||||
// cannot be added or removed dynamically.
|
||||
private FloatingHeaderRow[] mFixedRows = FloatingHeaderRow.NO_ROWS;
|
||||
|
||||
// Array of all fixed rows and plugin rows. This is initialized every time a plugin is
|
||||
// enabled or disabled, and represent the current set of all rows.
|
||||
private FloatingHeaderRow[] mAllRows = FloatingHeaderRow.NO_ROWS;
|
||||
|
||||
public FloatingHeaderView(@NonNull Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public FloatingHeaderView(@NonNull Context context, @Nullable AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
mPluginRows = new HashMap<>();
|
||||
mPluginRowViews = new ArrayList<>();
|
||||
mHeaderTopPadding = context.getResources()
|
||||
.getDimensionPixelSize(R.dimen.all_apps_header_top_padding);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onFinishInflate() {
|
||||
super.onFinishInflate();
|
||||
mTabLayout = findViewById(R.id.tabs);
|
||||
|
||||
// Find all floating header rows.
|
||||
ArrayList<FloatingHeaderRow> rows = new ArrayList<>();
|
||||
int count = getChildCount();
|
||||
for (int i = 0; i < count; i++) {
|
||||
View child = getChildAt(i);
|
||||
if (child instanceof FloatingHeaderRow) {
|
||||
rows.add((FloatingHeaderRow) child);
|
||||
}
|
||||
}
|
||||
mFixedRows = rows.toArray(new FloatingHeaderRow[rows.size()]);
|
||||
mAllRows = mFixedRows;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -114,50 +143,70 @@ public class FloatingHeaderView extends LinearLayout implements
|
||||
PluginManagerWrapper.INSTANCE.get(getContext()).removePluginListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPluginConnected(AllAppsRow allAppsRowPlugin, Context context) {
|
||||
mPluginRows.put(allAppsRowPlugin, null);
|
||||
setupPluginRows();
|
||||
allAppsRowPlugin.setOnHeightUpdatedListener(this::onPluginRowHeightUpdated);
|
||||
private void recreateAllRowsArray() {
|
||||
int pluginCount = mPluginRows.size();
|
||||
if (pluginCount == 0) {
|
||||
mAllRows = mFixedRows;
|
||||
} else {
|
||||
int count = mFixedRows.length;
|
||||
mAllRows = new FloatingHeaderRow[count + pluginCount];
|
||||
for (int i = 0; i < count; i++) {
|
||||
mAllRows[i] = mFixedRows[i];
|
||||
}
|
||||
|
||||
for (PluginHeaderRow row : mPluginRows.values()) {
|
||||
mAllRows[count] = row;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void onPluginRowHeightUpdated() {
|
||||
@Override
|
||||
public void onPluginConnected(AllAppsRow allAppsRowPlugin, Context context) {
|
||||
PluginHeaderRow headerRow = new PluginHeaderRow(allAppsRowPlugin, this);
|
||||
addView(headerRow.mView, indexOfChild(mTabLayout));
|
||||
mPluginRows.put(allAppsRowPlugin, headerRow);
|
||||
recreateAllRowsArray();
|
||||
allAppsRowPlugin.setOnHeightUpdatedListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onHeightUpdated() {
|
||||
int oldMaxHeight = mMaxTranslation;
|
||||
updateExpectedHeight();
|
||||
|
||||
if (mMaxTranslation != oldMaxHeight) {
|
||||
AllAppsContainerView parent = (AllAppsContainerView) getParent();
|
||||
if (parent != null) {
|
||||
parent.setupHeader();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPluginDisconnected(AllAppsRow plugin) {
|
||||
View pluginRowView = mPluginRows.get(plugin);
|
||||
removeView(pluginRowView);
|
||||
PluginHeaderRow row = mPluginRows.get(plugin);
|
||||
removeView(row.mView);
|
||||
mPluginRows.remove(plugin);
|
||||
mPluginRowViews.remove(pluginRowView);
|
||||
onPluginRowHeightUpdated();
|
||||
recreateAllRowsArray();
|
||||
onHeightUpdated();
|
||||
}
|
||||
|
||||
public void setup(AllAppsContainerView.AdapterHolder[] mAH, boolean tabsHidden) {
|
||||
for (FloatingHeaderRow row : mAllRows) {
|
||||
row.setup(this, mAllRows, tabsHidden);
|
||||
}
|
||||
updateExpectedHeight();
|
||||
|
||||
mTabsHidden = tabsHidden;
|
||||
mTabLayout.setVisibility(tabsHidden ? View.GONE : View.VISIBLE);
|
||||
mMainRV = setupRV(mMainRV, mAH[AllAppsContainerView.AdapterHolder.MAIN].recyclerView);
|
||||
mWorkRV = setupRV(mWorkRV, mAH[AllAppsContainerView.AdapterHolder.WORK].recyclerView);
|
||||
mParent = (ViewGroup) mMainRV.getParent();
|
||||
setMainActive(mMainRVActive || mWorkRV == null);
|
||||
setupPluginRows();
|
||||
reset(false);
|
||||
}
|
||||
|
||||
private void setupPluginRows() {
|
||||
for (Map.Entry<AllAppsRow, View> rowPluginEntry : mPluginRows.entrySet()) {
|
||||
if (rowPluginEntry.getValue() == null) {
|
||||
View pluginRow = rowPluginEntry.getKey().setup(this);
|
||||
addView(pluginRow, indexOfChild(mTabLayout));
|
||||
rowPluginEntry.setValue(pluginRow);
|
||||
mPluginRowViews.add(pluginRow);
|
||||
}
|
||||
}
|
||||
for (View plugin : mPluginRowViews) {
|
||||
plugin.setVisibility(mHeaderCollapsed ? GONE : VISIBLE);
|
||||
}
|
||||
}
|
||||
|
||||
private AllAppsRecyclerView setupRV(AllAppsRecyclerView old, AllAppsRecyclerView updated) {
|
||||
if (old != updated && updated != null ) {
|
||||
updated.addOnScrollListener(mOnScrollListener);
|
||||
@@ -165,6 +214,16 @@ public class FloatingHeaderView extends LinearLayout implements
|
||||
return updated;
|
||||
}
|
||||
|
||||
private void updateExpectedHeight() {
|
||||
mMaxTranslation = 0;
|
||||
if (mCollapsed) {
|
||||
return;
|
||||
}
|
||||
for (FloatingHeaderRow row : mAllRows) {
|
||||
mMaxTranslation += row.getExpectedHeight();
|
||||
}
|
||||
}
|
||||
|
||||
public void setMainActive(boolean active) {
|
||||
mCurrentRV = active ? mMainRV : mWorkRV;
|
||||
mMainRVActive = active;
|
||||
@@ -208,12 +267,21 @@ public class FloatingHeaderView extends LinearLayout implements
|
||||
}
|
||||
}
|
||||
|
||||
protected void applyScroll(int uncappedY, int currentY) { }
|
||||
|
||||
protected void apply() {
|
||||
protected void applyVerticalMove() {
|
||||
int uncappedTranslationY = mTranslationY;
|
||||
mTranslationY = Math.max(mTranslationY, -mMaxTranslation);
|
||||
applyScroll(uncappedTranslationY, mTranslationY);
|
||||
|
||||
if (mCollapsed || uncappedTranslationY < mTranslationY - mHeaderTopPadding) {
|
||||
// we hide it completely if already capped (for opening search anim)
|
||||
for (FloatingHeaderRow row : mAllRows) {
|
||||
row.setVerticalScroll(0, true /* isScrolledOut */);
|
||||
}
|
||||
} else {
|
||||
for (FloatingHeaderRow row : mAllRows) {
|
||||
row.setVerticalScroll(uncappedTranslationY, false /* isScrolledOut */);
|
||||
}
|
||||
}
|
||||
|
||||
mTabLayout.setTranslationY(mTranslationY);
|
||||
mClip.top = mMaxTranslation + mTranslationY;
|
||||
// clipping on a draw might cause additional redraw
|
||||
@@ -223,6 +291,16 @@ public class FloatingHeaderView extends LinearLayout implements
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Hides all the floating rows
|
||||
*/
|
||||
public void setCollapsed(boolean collapse) {
|
||||
if (mCollapsed == collapse) return;
|
||||
|
||||
mCollapsed = collapse;
|
||||
onHeightUpdated();
|
||||
}
|
||||
|
||||
public void reset(boolean animate) {
|
||||
if (mAnimator.isStarted()) {
|
||||
mAnimator.cancel();
|
||||
@@ -234,7 +312,7 @@ public class FloatingHeaderView extends LinearLayout implements
|
||||
mAnimator.start();
|
||||
} else {
|
||||
mTranslationY = 0;
|
||||
apply();
|
||||
applyVerticalMove();
|
||||
}
|
||||
mHeaderCollapsed = false;
|
||||
mSnappedScrolledY = -mMaxTranslation;
|
||||
@@ -248,7 +326,7 @@ public class FloatingHeaderView extends LinearLayout implements
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator animation) {
|
||||
mTranslationY = (Integer) animation.getAnimatedValue();
|
||||
apply();
|
||||
applyVerticalMove();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -287,8 +365,12 @@ public class FloatingHeaderView extends LinearLayout implements
|
||||
|
||||
public void setContentVisibility(boolean hasHeader, boolean hasContent, PropertySetter setter,
|
||||
Interpolator fadeInterpolator) {
|
||||
setter.setViewAlpha(this, hasContent ? 1 : 0, fadeInterpolator);
|
||||
for (FloatingHeaderRow row : mAllRows) {
|
||||
row.setContentVisibility(hasHeader, hasContent, setter, fadeInterpolator);
|
||||
}
|
||||
|
||||
allowTouchForwarding(hasContent);
|
||||
setter.setFloat(mTabLayout, ALPHA, hasContent ? 1 : 0, fadeInterpolator);
|
||||
}
|
||||
|
||||
protected void allowTouchForwarding(boolean allow) {
|
||||
@@ -296,6 +378,11 @@ public class FloatingHeaderView extends LinearLayout implements
|
||||
}
|
||||
|
||||
public boolean hasVisibleContent() {
|
||||
for (FloatingHeaderRow row : mAllRows) {
|
||||
if (row.hasVisibleContent()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -303,6 +390,23 @@ public class FloatingHeaderView extends LinearLayout implements
|
||||
public boolean hasOverlappingRendering() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setInsets(Rect insets) {
|
||||
DeviceProfile grid = Launcher.getLauncher(getContext()).getDeviceProfile();
|
||||
for (FloatingHeaderRow row : mAllRows) {
|
||||
row.setInsets(insets, grid);
|
||||
}
|
||||
}
|
||||
|
||||
public <T extends FloatingHeaderRow> T findFixedRowByType(Class<T> type) {
|
||||
for (FloatingHeaderRow row : mAllRows) {
|
||||
if (row.getTypeClass() == type) {
|
||||
return (T) row;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright (C) 2018 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.allapps;
|
||||
|
||||
import static android.view.View.ALPHA;
|
||||
import static android.view.View.INVISIBLE;
|
||||
import static android.view.View.VISIBLE;
|
||||
|
||||
import android.graphics.Rect;
|
||||
import android.view.View;
|
||||
import android.view.animation.Interpolator;
|
||||
|
||||
import com.android.launcher3.DeviceProfile;
|
||||
import com.android.launcher3.anim.PropertySetter;
|
||||
import com.android.systemui.plugins.AllAppsRow;
|
||||
|
||||
/**
|
||||
* Wrapper over an {@link AllAppsRow} plugin with {@link FloatingHeaderRow} interface so that
|
||||
* it can be easily added in {@link FloatingHeaderView}.
|
||||
*/
|
||||
public class PluginHeaderRow implements FloatingHeaderRow {
|
||||
|
||||
private final AllAppsRow mPlugin;
|
||||
final View mView;
|
||||
|
||||
PluginHeaderRow(AllAppsRow plugin, FloatingHeaderView parent) {
|
||||
mPlugin = plugin;
|
||||
mView = mPlugin.setup(parent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setup(FloatingHeaderView parent, FloatingHeaderRow[] allRows,
|
||||
boolean tabsHidden) { }
|
||||
|
||||
@Override
|
||||
public void setInsets(Rect insets, DeviceProfile grid) { }
|
||||
|
||||
@Override
|
||||
public int getExpectedHeight() {
|
||||
return mPlugin.getExpectedHeight();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldDraw() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasVisibleContent() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContentVisibility(boolean hasHeaderExtra, boolean hasContent,
|
||||
PropertySetter setter, Interpolator fadeInterpolator) {
|
||||
// Don't use setViewAlpha as we want to control the visibility ourselves.
|
||||
setter.setFloat(mView, ALPHA, hasContent ? 1 : 0, fadeInterpolator);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setVerticalScroll(int scroll, boolean isScrolledOut) {
|
||||
mView.setVisibility(isScrolledOut ? INVISIBLE : VISIBLE);
|
||||
if (!isScrolledOut) {
|
||||
mView.setTranslationY(scroll);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<PluginHeaderRow> getTypeClass() {
|
||||
return PluginHeaderRow.class;
|
||||
}
|
||||
}
|
||||
@@ -36,7 +36,7 @@ import com.android.launcher3.MainThreadExecutor;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.folder.FolderIcon;
|
||||
import com.android.launcher3.folder.PreviewBackground;
|
||||
import com.android.launcher3.graphics.BitmapRenderer;
|
||||
import com.android.launcher3.icons.BitmapRenderer;
|
||||
import com.android.launcher3.util.Preconditions;
|
||||
|
||||
/**
|
||||
|
||||
@@ -33,6 +33,7 @@ import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.config.FeatureFlags;
|
||||
import com.android.launcher3.folder.FolderIcon;
|
||||
import com.android.launcher3.icons.BitmapRenderer;
|
||||
import com.android.launcher3.util.UiThreadHelper;
|
||||
import com.android.launcher3.widget.LauncherAppWidgetHostView;
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@ import android.os.Build;
|
||||
import android.util.AttributeSet;
|
||||
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.icons.BitmapRenderer;
|
||||
|
||||
import org.xmlpull.v1.XmlPullParser;
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
|
||||
@@ -36,19 +36,14 @@ import android.graphics.drawable.Drawable;
|
||||
import android.os.Build;
|
||||
import android.os.Build.VERSION;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.Process;
|
||||
import android.os.UserHandle;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.launcher3.IconProvider;
|
||||
import com.android.launcher3.LauncherFiles;
|
||||
import com.android.launcher3.LauncherModel;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.compat.UserManagerCompat;
|
||||
import com.android.launcher3.graphics.BitmapRenderer;
|
||||
import com.android.launcher3.util.ComponentKey;
|
||||
import com.android.launcher3.util.InstantAppResolver;
|
||||
import com.android.launcher3.util.Preconditions;
|
||||
import com.android.launcher3.util.Provider;
|
||||
import com.android.launcher3.util.SQLiteCacheHelper;
|
||||
@@ -58,11 +53,10 @@ import java.util.HashSet;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
public class BaseIconCache {
|
||||
public abstract class BaseIconCache {
|
||||
|
||||
private static final String TAG = "BaseIconCache";
|
||||
private static final boolean DEBUG = false;
|
||||
private static final boolean DEBUG_IGNORE_CACHE = false;
|
||||
|
||||
private static final int INITIAL_ICON_CACHE_CAPACITY = 50;
|
||||
|
||||
@@ -76,29 +70,30 @@ public class BaseIconCache {
|
||||
|
||||
private final HashMap<UserHandle, BitmapInfo> mDefaultIcons = new HashMap<>();
|
||||
|
||||
final Context mContext;
|
||||
final PackageManager mPackageManager;
|
||||
final IconProvider mIconProvider;
|
||||
final UserManagerCompat mUserManager;
|
||||
protected final Context mContext;
|
||||
protected final PackageManager mPackageManager;
|
||||
protected final IconProvider mIconProvider;
|
||||
|
||||
private final HashMap<ComponentKey, CacheEntry> mCache =
|
||||
new HashMap<>(INITIAL_ICON_CACHE_CAPACITY);
|
||||
private final InstantAppResolver mInstantAppResolver;
|
||||
final Handler mWorkerHandler;
|
||||
protected final Handler mWorkerHandler;
|
||||
|
||||
int mIconDpi;
|
||||
protected int mIconDpi;
|
||||
IconDB mIconDb;
|
||||
|
||||
private final String mDbFileName;
|
||||
private final BitmapFactory.Options mDecodeOptions;
|
||||
private final Looper mBgLooper;
|
||||
|
||||
public BaseIconCache(Context context, int iconDpi, int iconPixelSize) {
|
||||
public BaseIconCache(Context context, String dbFileName, Looper bgLooper,
|
||||
int iconDpi, int iconPixelSize) {
|
||||
mContext = context;
|
||||
mDbFileName = dbFileName;
|
||||
mPackageManager = context.getPackageManager();
|
||||
mUserManager = UserManagerCompat.getInstance(mContext);
|
||||
mInstantAppResolver = InstantAppResolver.newInstance(mContext);
|
||||
mBgLooper = bgLooper;
|
||||
|
||||
mIconProvider = IconProvider.newInstance(context);
|
||||
mWorkerHandler = new Handler(LauncherModel.getWorkerLooper());
|
||||
mWorkerHandler = new Handler(mBgLooper);
|
||||
|
||||
if (BitmapRenderer.USE_HARDWARE_BITMAP && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
mDecodeOptions = new BitmapFactory.Options();
|
||||
@@ -108,9 +103,21 @@ public class BaseIconCache {
|
||||
}
|
||||
|
||||
mIconDpi = iconDpi;
|
||||
mIconDb = new IconDB(context, iconPixelSize);
|
||||
mIconDb = new IconDB(context, dbFileName, iconPixelSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the persistable serial number for {@param user}. Subclass should implement proper
|
||||
* caching strategy to avoid making binder call every time.
|
||||
*/
|
||||
protected abstract long getSerialNumberForUser(UserHandle user);
|
||||
|
||||
/**
|
||||
* Return true if the given app is an instant app and should be badged appropriately.
|
||||
*/
|
||||
protected abstract boolean isInstantApp(ApplicationInfo info);
|
||||
|
||||
|
||||
public void updateIconParams(int iconDpi, int iconPixelSize) {
|
||||
mWorkerHandler.post(() -> updateIconParamsBg(iconDpi, iconPixelSize));
|
||||
}
|
||||
@@ -120,13 +127,14 @@ public class BaseIconCache {
|
||||
mDefaultIcons.clear();
|
||||
|
||||
mIconDb.close();
|
||||
mIconDb = new IconDB(mContext, iconPixelSize);
|
||||
mIconDb = new IconDB(mContext, mDbFileName, iconPixelSize);
|
||||
mCache.clear();
|
||||
}
|
||||
|
||||
private Drawable getFullResDefaultActivityIcon() {
|
||||
return Resources.getSystem().getDrawableForDensity(Utilities.ATLEAST_OREO
|
||||
? android.R.drawable.sym_def_app_icon : android.R.mipmap.sym_def_app_icon,
|
||||
return Resources.getSystem().getDrawableForDensity(
|
||||
Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
|
||||
? android.R.drawable.sym_def_app_icon : android.R.mipmap.sym_def_app_icon,
|
||||
mIconDpi);
|
||||
}
|
||||
|
||||
@@ -189,7 +197,7 @@ public class BaseIconCache {
|
||||
*/
|
||||
public synchronized void removeIconsForPkg(String packageName, UserHandle user) {
|
||||
removeFromMemCacheLocked(packageName, user);
|
||||
long userSerial = mUserManager.getSerialNumberForUser(user);
|
||||
long userSerial = getSerialNumberForUser(user);
|
||||
mIconDb.delete(
|
||||
IconDB.COLUMN_COMPONENT + " LIKE ? AND " + IconDB.COLUMN_USER + " = ?",
|
||||
new String[]{packageName + "/%", Long.toString(userSerial)});
|
||||
@@ -287,7 +295,7 @@ public class BaseIconCache {
|
||||
T object = null;
|
||||
boolean providerFetchedOnce = false;
|
||||
|
||||
if (!getEntryFromDB(cacheKey, entry, useLowResIcon) || DEBUG_IGNORE_CACHE) {
|
||||
if (!getEntryFromDB(cacheKey, entry, useLowResIcon)) {
|
||||
object = infoProvider.get();
|
||||
providerFetchedOnce = true;
|
||||
|
||||
@@ -395,7 +403,7 @@ public class BaseIconCache {
|
||||
// only keep the low resolution icon instead of the larger full-sized icon
|
||||
BitmapInfo iconInfo = li.createBadgedIconBitmap(
|
||||
appInfo.loadIcon(mPackageManager), user, appInfo.targetSdkVersion,
|
||||
mInstantAppResolver.isInstantApp(appInfo));
|
||||
isInstantApp(appInfo));
|
||||
li.recycle();
|
||||
|
||||
entry.title = appInfo.loadLabel(mPackageManager);
|
||||
@@ -407,8 +415,7 @@ public class BaseIconCache {
|
||||
// package updates.
|
||||
ContentValues values = newContentValues(
|
||||
iconInfo, entry.title.toString(), packageName);
|
||||
addIconToDB(values, cacheKey.componentName, info,
|
||||
mUserManager.getSerialNumberForUser(user));
|
||||
addIconToDB(values, cacheKey.componentName, info, getSerialNumberForUser(user));
|
||||
|
||||
} catch (NameNotFoundException e) {
|
||||
if (DEBUG) Log.d(TAG, "Application not installed " + packageName);
|
||||
@@ -432,7 +439,7 @@ public class BaseIconCache {
|
||||
IconDB.COLUMN_COMPONENT + " = ? AND " + IconDB.COLUMN_USER + " = ?",
|
||||
new String[]{
|
||||
cacheKey.componentName.flattenToString(),
|
||||
Long.toString(mUserManager.getSerialNumberForUser(cacheKey.user))});
|
||||
Long.toString(getSerialNumberForUser(cacheKey.user))});
|
||||
if (c.moveToNext()) {
|
||||
// Set the alpha to be 255, so that we never have a wrong color
|
||||
entry.color = setColorAlphaBound(c.getInt(0), 255);
|
||||
@@ -485,10 +492,8 @@ public class BaseIconCache {
|
||||
public final static String[] COLUMNS_LOW_RES = new String[] {
|
||||
IconDB.COLUMN_ICON_COLOR, IconDB.COLUMN_LABEL };
|
||||
|
||||
public IconDB(Context context, int iconPixelSize) {
|
||||
super(context, LauncherFiles.APP_ICONS_DB,
|
||||
(RELEASE_VERSION << 16) + iconPixelSize,
|
||||
TABLE_NAME);
|
||||
public IconDB(Context context, String dbFileName, int iconPixelSize) {
|
||||
super(context, dbFileName, (RELEASE_VERSION << 16) + iconPixelSize, TABLE_NAME);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -510,7 +515,7 @@ public class BaseIconCache {
|
||||
private ContentValues newContentValues(BitmapInfo bitmapInfo, String label, String packageName) {
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(IconDB.COLUMN_ICON,
|
||||
bitmapInfo.isLowRes() ? null : Utilities.flattenBitmap(bitmapInfo.icon));
|
||||
bitmapInfo.isLowRes() ? null : GraphicsUtils.flattenBitmap(bitmapInfo.icon));
|
||||
values.put(IconDB.COLUMN_ICON_COLOR, bitmapInfo.color);
|
||||
|
||||
values.put(IconDB.COLUMN_LABEL, label);
|
||||
|
||||
@@ -18,6 +18,7 @@ package com.android.launcher3.icons;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.LauncherActivityInfo;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
@@ -31,13 +32,16 @@ import android.util.Log;
|
||||
import com.android.launcher3.AppInfo;
|
||||
import com.android.launcher3.InvariantDeviceProfile;
|
||||
import com.android.launcher3.ItemInfoWithIcon;
|
||||
import com.android.launcher3.LauncherFiles;
|
||||
import com.android.launcher3.LauncherModel;
|
||||
import com.android.launcher3.MainThreadExecutor;
|
||||
import com.android.launcher3.ShortcutInfo;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.compat.LauncherAppsCompat;
|
||||
import com.android.launcher3.compat.UserManagerCompat;
|
||||
import com.android.launcher3.icons.ComponentWithLabel.ComponentCachingLogic;
|
||||
import com.android.launcher3.model.PackageItemInfo;
|
||||
import com.android.launcher3.util.InstantAppResolver;
|
||||
import com.android.launcher3.util.Preconditions;
|
||||
import com.android.launcher3.util.Provider;
|
||||
|
||||
@@ -56,15 +60,29 @@ public class IconCache extends BaseIconCache {
|
||||
private final CachingLogic<LauncherActivityInfo> mLauncherActivityInfoCachingLogic;
|
||||
|
||||
private final LauncherAppsCompat mLauncherApps;
|
||||
private final UserManagerCompat mUserManager;
|
||||
private final InstantAppResolver mInstantAppResolver;
|
||||
|
||||
private int mPendingIconRequestCount = 0;
|
||||
|
||||
public IconCache(Context context, InvariantDeviceProfile inv) {
|
||||
super(context, inv.fillResIconDpi, inv.iconBitmapSize);
|
||||
super(context, LauncherFiles.APP_ICONS_DB, LauncherModel.getWorkerLooper(),
|
||||
inv.fillResIconDpi, inv.iconBitmapSize);
|
||||
mComponentWithLabelCachingLogic = new ComponentCachingLogic(context);
|
||||
mLauncherActivityInfoCachingLogic = new LauncherActivtiyCachingLogic(this);
|
||||
mLauncherApps = LauncherAppsCompat.getInstance(mContext);
|
||||
mUserManager = UserManagerCompat.getInstance(mContext);
|
||||
mInstantAppResolver = InstantAppResolver.newInstance(mContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected long getSerialNumberForUser(UserHandle user) {
|
||||
return mUserManager.getSerialNumberForUser(user);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isInstantApp(ApplicationInfo info) {
|
||||
return mInstantAppResolver.isInstantApp(info);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -27,11 +27,8 @@ import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.util.SparseBooleanArray;
|
||||
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.icons.BaseIconCache.IconDB;
|
||||
import com.android.launcher3.util.IntArray;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
@@ -131,7 +128,7 @@ public class IconCacheUpdateHandler {
|
||||
if (ignorePackages == null) {
|
||||
ignorePackages = Collections.emptySet();
|
||||
}
|
||||
long userSerial = mIconCache.mUserManager.getSerialNumberForUser(user);
|
||||
long userSerial = mIconCache.getSerialNumberForUser(user);
|
||||
|
||||
Stack<T> appsToUpdate = new Stack<>();
|
||||
|
||||
@@ -204,18 +201,31 @@ public class IconCacheUpdateHandler {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Commits all updates as part of the update handler to disk. Not more calls should be made
|
||||
* to this class after this.
|
||||
*/
|
||||
public void finish() {
|
||||
// Commit all deletes
|
||||
IntArray deleteIds = new IntArray();
|
||||
int deleteCount = 0;
|
||||
StringBuilder queryBuilder = new StringBuilder()
|
||||
.append(IconDB.COLUMN_ROWID)
|
||||
.append(" IN (");
|
||||
|
||||
int count = mItemsToDelete.size();
|
||||
for (int i = 0; i < count; i++) {
|
||||
if (mItemsToDelete.valueAt(i)) {
|
||||
deleteIds.add(mItemsToDelete.keyAt(i));
|
||||
if (deleteCount > 0) {
|
||||
queryBuilder.append(", ");
|
||||
}
|
||||
queryBuilder.append(mItemsToDelete.keyAt(i));
|
||||
deleteCount++;
|
||||
}
|
||||
}
|
||||
if (!deleteIds.isEmpty()) {
|
||||
mIconCache.mIconDb.delete(
|
||||
Utilities.createDbSelectionQuery(IconDB.COLUMN_ROWID, deleteIds), null);
|
||||
queryBuilder.append(')');
|
||||
|
||||
if (deleteCount > 0) {
|
||||
mIconCache.mIconDb.delete(queryBuilder.toString(), null);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -31,7 +31,6 @@ import com.android.launcher3.InvariantDeviceProfile;
|
||||
import com.android.launcher3.ItemInfoWithIcon;
|
||||
import com.android.launcher3.LauncherAppState;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.graphics.BitmapRenderer;
|
||||
import com.android.launcher3.model.PackageItemInfo;
|
||||
import com.android.launcher3.shortcuts.DeepShortcutManager;
|
||||
import com.android.launcher3.shortcuts.ShortcutInfoCompat;
|
||||
|
||||
@@ -25,8 +25,8 @@ import android.os.UserHandle;
|
||||
|
||||
import com.android.launcher3.LauncherAppState;
|
||||
import com.android.launcher3.LauncherSettings;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.compat.UserManagerCompat;
|
||||
import com.android.launcher3.icons.GraphicsUtils;
|
||||
|
||||
/**
|
||||
* A wrapper around {@link ContentValues} with some utility methods.
|
||||
@@ -97,7 +97,7 @@ public class ContentWriter {
|
||||
Preconditions.assertNonUiThread();
|
||||
if (mIcon != null && !LauncherAppState.getInstance(context).getIconCache()
|
||||
.isDefaultIcon(mIcon, mUser)) {
|
||||
mValues.put(LauncherSettings.Favorites.ICON, Utilities.flattenBitmap(mIcon));
|
||||
mValues.put(LauncherSettings.Favorites.ICON, GraphicsUtils.flattenBitmap(mIcon));
|
||||
mIcon = null;
|
||||
}
|
||||
return mValues;
|
||||
|
||||
@@ -177,7 +177,7 @@ public final class LauncherInstrumentation {
|
||||
|
||||
switch (containerType) {
|
||||
case WORKSPACE: {
|
||||
waitUntilGone(APPS_RES_ID);
|
||||
waitForLauncherObject(APPS_RES_ID);
|
||||
waitUntilGone(OVERVIEW_RES_ID);
|
||||
waitUntilGone(WIDGETS_RES_ID);
|
||||
return waitForLauncherObject(WORKSPACE_RES_ID);
|
||||
|
||||
Reference in New Issue
Block a user