Snap for 9386067 from 969606e2ba to udc-release

Change-Id: I90a7fe9a852564b6896ad08eed1f7882209a5c94
This commit is contained in:
Android Build Coastguard Worker
2022-12-09 03:55:46 +00:00
23 changed files with 488 additions and 451 deletions
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2022 The Android Open Source Project
* 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.
@@ -16,23 +16,19 @@
package com.android.launcher3;
import android.animation.AnimatorSet;
import android.annotation.Nullable;
import android.annotation.TargetApi;
import android.os.Build;
import android.os.CancellationSignal;
import android.view.RemoteAnimationTarget;
import com.android.launcher3.uioverrides.QuickstepLauncher;
import com.android.quickstep.util.ActivityLifecycleListener;
import com.android.quickstep.util.ActivityInitListener;
import com.android.quickstep.util.RemoteAnimationProvider;
import java.util.function.BiPredicate;
/**
* {@link ActivityLifecycleListener} for the in-launcher recents.
*/
@TargetApi(Build.VERSION_CODES.P)
public class LauncherLifecycleListener extends ActivityLifecycleListener<Launcher> {
public class LauncherInitListener extends ActivityInitListener<Launcher> {
private RemoteAnimationProvider mRemoteAnimationProvider;
@@ -40,16 +36,13 @@ public class LauncherLifecycleListener extends ActivityLifecycleListener<Launche
* @param onInitListener a callback made when the activity is initialized. The callback should
* return true to continue receiving callbacks (ie. for if the activity is
* recreated).
* @param onDestroyListener a callback made when the activity is destroyed.
*/
public LauncherLifecycleListener(
@Nullable BiPredicate<Launcher, Boolean> onInitListener,
@Nullable Runnable onDestroyListener) {
super(onInitListener, onDestroyListener, Launcher.ACTIVITY_TRACKER);
public LauncherInitListener(BiPredicate<Launcher, Boolean> onInitListener) {
super(onInitListener, Launcher.ACTIVITY_TRACKER);
}
@Override
public boolean handleActivityReady(Launcher launcher, boolean alreadyOnHome) {
public boolean handleInit(Launcher launcher, boolean alreadyOnHome) {
if (mRemoteAnimationProvider != null) {
QuickstepTransitionManager appTransitionManager =
((QuickstepLauncher) launcher).getAppTransitionManager();
@@ -75,7 +68,7 @@ public class LauncherLifecycleListener extends ActivityLifecycleListener<Launche
}, cancellationSignal);
}
launcher.deferOverlayCallbacksUntilNextResumeOrStop();
return super.handleActivityReady(launcher, alreadyOnHome);
return super.handleInit(launcher, alreadyOnHome);
}
@Override
@@ -50,7 +50,6 @@ import static com.android.quickstep.GestureState.STATE_RECENTS_SCROLLING_FINISHE
import static com.android.quickstep.MultiStateCallback.DEBUG_STATES;
import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.CANCEL_RECENTS_ANIMATION;
import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.EXPECTING_TASK_APPEARED;
import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.LAUNCHER_DESTROYED;
import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.ON_SETTLED_ON_END_TARGET;
import static com.android.quickstep.util.VibratorWrapper.OVERVIEW_HAPTIC;
import static com.android.quickstep.views.RecentsView.UPDATE_SYSUI_FLAGS_THRESHOLD;
@@ -114,7 +113,7 @@ import com.android.quickstep.GestureState.GestureEndTarget;
import com.android.quickstep.RemoteTargetGluer.RemoteTargetHandle;
import com.android.quickstep.util.ActiveGestureErrorDetector;
import com.android.quickstep.util.ActiveGestureLog;
import com.android.quickstep.util.ActivityLifecycleListener;
import com.android.quickstep.util.ActivityInitListener;
import com.android.quickstep.util.AnimatorControllerWithResistance;
import com.android.quickstep.util.InputConsumerProxy;
import com.android.quickstep.util.InputProxyHandlerFactory;
@@ -160,7 +159,7 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>,
protected final BaseActivityInterface<S, T> mActivityInterface;
protected final InputConsumerProxy mInputConsumerProxy;
protected final ActivityLifecycleListener mActivityInitListener;
protected final ActivityInitListener mActivityInitListener;
// Callbacks to be made once the recents animation starts
private final ArrayList<Runnable> mRecentsAnimationStartCallbacks = new ArrayList<>();
private final OnScrollChangedListener mOnRecentsScrollListener = this::onRecentsViewScroll;
@@ -329,8 +328,7 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>,
InputConsumerController inputConsumer) {
super(context, deviceState, gestureState);
mActivityInterface = gestureState.getActivityInterface();
mActivityInitListener = mActivityInterface.createActivityLifecycleListener(
this::onActivityInit, this::onActivityDestroy);
mActivityInitListener = mActivityInterface.createActivityInitListener(this::onActivityInit);
mInputConsumerProxy =
new InputConsumerProxy(context, /* rotationSupplier = */ () -> {
if (mRecentsView == null) {
@@ -521,11 +519,6 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>,
return true;
}
private void onActivityDestroy() {
ActiveGestureLog.INSTANCE.addLog("Launcher activity destroyed", LAUNCHER_DESTROYED);
onGestureCancelled();
}
/**
* Return true if the window should be translated horizontally if the recents view scrolls
*/
@@ -60,7 +60,7 @@ import com.android.launcher3.touch.PagedOrientationHandler;
import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.NavigationMode;
import com.android.launcher3.views.ScrimView;
import com.android.quickstep.util.ActivityLifecycleListener;
import com.android.quickstep.util.ActivityInitListener;
import com.android.quickstep.util.AnimatorControllerWithResistance;
import com.android.quickstep.views.RecentsView;
import com.android.systemui.shared.recents.model.ThumbnailData;
@@ -123,17 +123,8 @@ public abstract class BaseActivityInterface<STATE_TYPE extends BaseState<STATE_T
public abstract AnimationFactory prepareRecentsUI(RecentsAnimationDeviceState deviceState,
boolean activityVisible, Consumer<AnimatorControllerWithResistance> callback);
/**
* Creates a activity listener for activity initialized and/or destroyed. One or both of these
* listeners must be provided.
*
* @param onInitListener a callback made when the activity is initialized. The callback should
* return true to continue receiving callbacks (ie. for if the activity is
* recreated).
* @param onDestroyListener a callback made when the activity is destroyed.
*/
public abstract ActivityLifecycleListener createActivityLifecycleListener(
@Nullable Predicate<Boolean> onInitListener, @Nullable Runnable onDestroyListener);
public abstract ActivityInitListener createActivityInitListener(
Predicate<Boolean> onInitListener);
/**
* Sets a callback to be run when an activity launch happens while launcher is not yet resumed.
@@ -36,7 +36,7 @@ import com.android.launcher3.touch.PagedOrientationHandler;
import com.android.launcher3.util.DisplayController;
import com.android.quickstep.GestureState.GestureEndTarget;
import com.android.quickstep.fallback.RecentsState;
import com.android.quickstep.util.ActivityLifecycleListener;
import com.android.quickstep.util.ActivityInitListener;
import com.android.quickstep.util.AnimatorControllerWithResistance;
import com.android.quickstep.views.RecentsView;
@@ -88,12 +88,10 @@ public final class FallbackActivityInterface extends
}
@Override
public ActivityLifecycleListener createActivityLifecycleListener(
@Nullable Predicate<Boolean> onInitListener, @Nullable Runnable onDestroyListener) {
return new ActivityLifecycleListener<>(
(activity, alreadyOnHome) -> onInitListener.test(alreadyOnHome),
onDestroyListener,
RecentsActivity.ACTIVITY_TRACKER);
public ActivityInitListener createActivityInitListener(
Predicate<Boolean> onInitListener) {
return new ActivityInitListener<>((activity, alreadyOnHome) ->
onInitListener.test(alreadyOnHome), RecentsActivity.ACTIVITY_TRACKER);
}
@Nullable
@@ -37,7 +37,7 @@ import androidx.annotation.UiThread;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAnimUtils;
import com.android.launcher3.LauncherLifecycleListener;
import com.android.launcher3.LauncherInitListener;
import com.android.launcher3.LauncherState;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.statehandlers.DepthController;
@@ -49,7 +49,7 @@ import com.android.launcher3.uioverrides.QuickstepLauncher;
import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.NavigationMode;
import com.android.quickstep.GestureState.GestureEndTarget;
import com.android.quickstep.util.ActivityLifecycleListener;
import com.android.quickstep.util.ActivityInitListener;
import com.android.quickstep.util.AnimatorControllerWithResistance;
import com.android.quickstep.util.LayoutUtils;
import com.android.quickstep.views.RecentsView;
@@ -136,10 +136,9 @@ public final class LauncherActivityInterface extends
}
@Override
public ActivityLifecycleListener createActivityLifecycleListener(
@Nullable Predicate<Boolean> onInitListener, @Nullable Runnable onDestroyListener) {
return new LauncherLifecycleListener((activity, alreadyOnHome) ->
onInitListener.test(alreadyOnHome), onDestroyListener);
public ActivityInitListener createActivityInitListener(Predicate<Boolean> onInitListener) {
return new LauncherInitListener((activity, alreadyOnHome) ->
onInitListener.test(alreadyOnHome));
}
@Override
@@ -37,7 +37,7 @@ public class ActiveGestureErrorDetector {
ON_SETTLED_ON_END_TARGET, START_RECENTS_ANIMATION, FINISH_RECENTS_ANIMATION,
CANCEL_RECENTS_ANIMATION, SET_ON_PAGE_TRANSITION_END_CALLBACK, CANCEL_CURRENT_ANIMATION,
CLEANUP_SCREENSHOT, SCROLLER_ANIMATION_ABORTED, TASK_APPEARED, EXPECTING_TASK_APPEARED,
FLAG_USING_OTHER_ACTIVITY_INPUT_CONSUMER, LAUNCHER_DESTROYED,
FLAG_USING_OTHER_ACTIVITY_INPUT_CONSUMER,
/**
* These GestureEvents are specifically associated to state flags that get set in
@@ -162,13 +162,6 @@ public class ActiveGestureErrorDetector {
+ "before/without setting end target to new task",
writer);
break;
case LAUNCHER_DESTROYED:
errorDetected |= printErrorIfTrue(
true,
prefix,
/* errorMessage= */ "Launcher destroyed mid-gesture",
writer);
break;
case STATE_GESTURE_COMPLETED:
errorDetected |= printErrorIfTrue(
!encounteredEvents.contains(GestureEvent.MOTION_UP),
@@ -0,0 +1,73 @@
/*
* Copyright (C) 2019 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.quickstep.util;
import com.android.launcher3.BaseActivity;
import com.android.launcher3.util.ActivityTracker;
import com.android.launcher3.util.ActivityTracker.SchedulerCallback;
import java.util.function.BiPredicate;
public class ActivityInitListener<T extends BaseActivity> implements
SchedulerCallback<T> {
private BiPredicate<T, Boolean> mOnInitListener;
private final ActivityTracker<T> mActivityTracker;
private boolean mIsRegistered = false;
/**
* @param onInitListener a callback made when the activity is initialized. The callback should
* return true to continue receiving callbacks (ie. for if the activity is
* recreated).
*/
public ActivityInitListener(BiPredicate<T, Boolean> onInitListener,
ActivityTracker<T> tracker) {
mOnInitListener = onInitListener;
mActivityTracker = tracker;
}
@Override
public final boolean init(T activity, boolean alreadyOnHome) {
if (!mIsRegistered) {
// Don't receive any more updates
return false;
}
return handleInit(activity, alreadyOnHome);
}
protected boolean handleInit(T activity, boolean alreadyOnHome) {
return mOnInitListener.test(activity, alreadyOnHome);
}
/**
* Registers the activity-created listener. If the activity is already created, then the
* callback provided in the constructor will be called synchronously.
*/
public void register() {
mIsRegistered = true;
mActivityTracker.registerCallback(this);
}
/**
* After calling this, we won't {@link #init} even when the activity is ready.
*/
public void unregister() {
mActivityTracker.unregisterCallback(this);
mIsRegistered = false;
mOnInitListener = null;
}
}
@@ -1,113 +0,0 @@
/*
* Copyright (C) 2022 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.quickstep.util;
import android.util.Log;
import androidx.annotation.Nullable;
import com.android.launcher3.BaseActivity;
import com.android.launcher3.util.ActivityTracker;
import com.android.launcher3.util.ActivityTracker.SchedulerCallback;
import java.util.function.BiPredicate;
/**
* Listener for activity initialized and/or destroyed.
*/
public class ActivityLifecycleListener<T extends BaseActivity> implements
SchedulerCallback<T> {
private static final String TAG = "ActivityLifecycleListener";
@Nullable private final BiPredicate<T, Boolean> mOnInitListener;
@Nullable private final Runnable mOnDestroyListener;
private final ActivityTracker<T> mActivityTracker;
private boolean mIsRegistered = false;
/**
* One or both of {@code onInitListener} and {@code onInitListener} must be provided, otherwise
* the created instance will effectively be a no-op.
*
* @param onInitListener a callback made when the activity is initialized. The callback should
* return true to continue receiving callbacks (ie. for if the activity is
* recreated).
* @param onDestroyListener a callback made when the activity is destroyed.
*/
public ActivityLifecycleListener(
@Nullable BiPredicate<T, Boolean> onInitListener,
@Nullable Runnable onDestroyListener,
ActivityTracker<T> tracker) {
if (onInitListener == null && onDestroyListener == null) {
throw new IllegalArgumentException("Both listeners cannot be null");
}
mOnInitListener = onInitListener;
mOnDestroyListener = onDestroyListener;
mActivityTracker = tracker;
}
@Override
public final boolean onActivityReady(T activity, boolean alreadyOnHome) {
if (!mIsRegistered) {
// Don't receive any more updates
return false;
}
return handleActivityReady(activity, alreadyOnHome);
}
protected boolean handleActivityReady(T activity, boolean alreadyOnHome) {
if (mOnInitListener == null) {
Log.e(TAG, "Cannot handle init: init listener is null", new Exception());
return false;
}
return mOnInitListener.test(activity, alreadyOnHome);
}
@Override
public void onActivityDestroyed() {
if (mOnDestroyListener == null) {
Log.e(TAG, "Cannot clean up: destroy listener is null", new Exception());
return;
}
mOnDestroyListener.run();
}
/**
* Registers the activity-created listener. If the activity is already created, then the
* callback provided in the constructor will be called synchronously.
*/
public void register() {
mIsRegistered = true;
mActivityTracker.registerCallback(this, getType());
}
/**
* After calling this, we won't call {@link #onActivityReady} even when the activity is ready.
*/
public void unregister() {
mActivityTracker.unregisterCallback(this, getType());
mIsRegistered = false;
}
private int getType() {
return mOnInitListener != null && mOnDestroyListener != null
? ActivityTracker.TYPE_BOTH
: (mOnInitListener != null
? ActivityTracker.TYPE_INIT
: ActivityTracker.TYPE_DESTROY);
}
}
@@ -31,7 +31,6 @@ import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.AttributeSet;
import android.util.Log;
import android.util.Pair;
import android.util.Patterns;
import android.util.Xml;
@@ -45,7 +44,7 @@ import com.android.launcher3.model.data.LauncherAppWidgetInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.qsb.QsbContainerView;
import com.android.launcher3.util.IntArray;
import com.android.launcher3.util.PackageManagerHelper;
import com.android.launcher3.util.Partner;
import com.android.launcher3.util.Thunk;
import com.android.launcher3.widget.LauncherWidgetHolder;
@@ -76,19 +75,16 @@ public class AutoInstallsLayout {
static AutoInstallsLayout get(Context context, LauncherWidgetHolder appWidgetHolder,
LayoutParserCallback callback) {
Pair<String, Resources> customizationApkInfo = PackageManagerHelper.findSystemApk(
ACTION_LAUNCHER_CUSTOMIZATION, context.getPackageManager());
if (customizationApkInfo == null) {
Partner partner = Partner.get(context.getPackageManager(), ACTION_LAUNCHER_CUSTOMIZATION);
if (partner == null) {
return null;
}
String pkg = customizationApkInfo.first;
Resources targetRes = customizationApkInfo.second;
InvariantDeviceProfile grid = LauncherAppState.getIDP(context);
// Try with grid size and hotseat count
String layoutName = String.format(Locale.ENGLISH, FORMATTED_LAYOUT_RES_WITH_HOSTEAT,
grid.numColumns, grid.numRows, grid.numDatabaseHotseatIcons);
int layoutId = targetRes.getIdentifier(layoutName, "xml", pkg);
int layoutId = partner.getXmlResId(layoutName);
// Try with only grid size
if (layoutId == 0) {
@@ -96,21 +92,21 @@ public class AutoInstallsLayout {
+ " not found. Trying layout without hosteat");
layoutName = String.format(Locale.ENGLISH, FORMATTED_LAYOUT_RES,
grid.numColumns, grid.numRows);
layoutId = targetRes.getIdentifier(layoutName, "xml", pkg);
layoutId = partner.getXmlResId(layoutName);
}
// Try the default layout
if (layoutId == 0) {
Log.d(TAG, "Formatted layout: " + layoutName + " not found. Trying the default layout");
layoutId = targetRes.getIdentifier(LAYOUT_RES, "xml", pkg);
layoutId = partner.getXmlResId(LAYOUT_RES);
}
if (layoutId == 0) {
Log.e(TAG, "Layout definition not found in package: " + pkg);
Log.e(TAG, "Layout definition not found in package: " + partner.getPackageName());
return null;
}
return new AutoInstallsLayout(context, appWidgetHolder, callback, targetRes, layoutId,
TAG_WORKSPACE);
return new AutoInstallsLayout(context, appWidgetHolder, callback, partner.getResources(),
layoutId, TAG_WORKSPACE);
}
// Object Tags
@@ -19,6 +19,7 @@ import android.util.Log;
import com.android.launcher3.LauncherSettings.Favorites;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.shortcuts.ShortcutKey;
import com.android.launcher3.util.Partner;
import com.android.launcher3.util.Thunk;
import com.android.launcher3.widget.LauncherWidgetHolder;
@@ -51,6 +52,9 @@ public class DefaultLayoutParser extends AutoInstallsLayout {
private static final String ATTR_SHORTCUT_ID = "shortcutId";
private static final String ATTR_PACKAGE_NAME = "packageName";
public static final String RES_PARTNER_FOLDER = "partner_folder";
public static final String RES_PARTNER_DEFAULT_LAYOUT = "partner_default_layout";
// TODO: Remove support for this broadcast, instead use widget options to send bind time options
private static final String ACTION_APPWIDGET_DEFAULT_WORKSPACE_CONFIGURE =
"com.android.launcher.action.APPWIDGET_DEFAULT_WORKSPACE_CONFIGURE";
@@ -278,10 +282,9 @@ public class DefaultLayoutParser extends AutoInstallsLayout {
// Folder contents come from an external XML resource
final Partner partner = Partner.get(mPackageManager);
if (partner != null) {
final Resources partnerRes = partner.getResources();
final int resId = partnerRes.getIdentifier(Partner.RES_FOLDER,
"xml", partner.getPackageName());
final int resId = partner.getXmlResId(RES_PARTNER_FOLDER);
if (resId != 0) {
final Resources partnerRes = partner.getResources();
final XmlPullParser partnerParser = partnerRes.getXml(resId);
beginDocument(partnerParser, TAG_FOLDER);
@@ -60,6 +60,7 @@ import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.DisplayController.Info;
import com.android.launcher3.util.IntArray;
import com.android.launcher3.util.MainThreadInitializedObject;
import com.android.launcher3.util.Partner;
import com.android.launcher3.util.Themes;
import com.android.launcher3.util.WindowBounds;
import com.android.launcher3.util.window.WindowManagerProxy;
@@ -112,6 +113,11 @@ public class InvariantDeviceProfile {
static final int INDEX_TWO_PANEL_PORTRAIT = 2;
static final int INDEX_TWO_PANEL_LANDSCAPE = 3;
/** These resources are used to override the device profile */
private static final String RES_GRID_NUM_ROWS = "grid_num_rows";
private static final String RES_GRID_NUM_COLUMNS = "grid_num_columns";
private static final String RES_GRID_ICON_SIZE_DP = "grid_icon_size_dp";
/**
* Number of icons per row and column in the workspace.
*/
@@ -567,8 +573,24 @@ public class InvariantDeviceProfile {
*/
private void applyPartnerDeviceProfileOverrides(Context context, DisplayMetrics dm) {
Partner p = Partner.get(context.getPackageManager());
if (p != null) {
p.applyInvariantDeviceProfileOverrides(this, dm);
if (p == null) {
return;
}
try {
int numRows = p.getIntValue(RES_GRID_NUM_ROWS, -1);
int numColumns = p.getIntValue(RES_GRID_NUM_COLUMNS, -1);
float iconSizePx = p.getDimenValue(RES_GRID_ICON_SIZE_DP, -1);
if (numRows > 0 && numColumns > 0) {
this.numRows = numRows;
this.numColumns = numColumns;
}
if (iconSizePx > 0) {
this.iconSize[InvariantDeviceProfile.INDEX_DEFAULT] =
Utilities.dpiFromPx(iconSizePx, dm.densityDpi);
}
} catch (Resources.NotFoundException ex) {
Log.e(TAG, "Invalid Partner grid resource!", ex);
}
}
@@ -16,6 +16,7 @@
package com.android.launcher3;
import static com.android.launcher3.DefaultLayoutParser.RES_PARTNER_DEFAULT_LAYOUT;
import static com.android.launcher3.provider.LauncherDbUtils.copyTable;
import static com.android.launcher3.provider.LauncherDbUtils.dropTable;
import static com.android.launcher3.provider.LauncherDbUtils.tableExists;
@@ -34,7 +35,6 @@ import android.content.Intent;
import android.content.OperationApplicationException;
import android.content.SharedPreferences;
import android.content.pm.ProviderInfo;
import android.content.res.Resources;
import android.database.Cursor;
import android.database.DatabaseUtils;
import android.database.SQLException;
@@ -70,6 +70,7 @@ import com.android.launcher3.util.IntArray;
import com.android.launcher3.util.IntSet;
import com.android.launcher3.util.NoLocaleSQLiteHelper;
import com.android.launcher3.util.PackageManagerHelper;
import com.android.launcher3.util.Partner;
import com.android.launcher3.util.Thunk;
import com.android.launcher3.widget.LauncherWidgetHolder;
@@ -544,13 +545,11 @@ public class LauncherProvider extends ContentProvider {
}
if (loader == null) {
final Partner partner = Partner.get(getContext().getPackageManager());
if (partner != null && partner.hasDefaultLayout()) {
final Resources partnerRes = partner.getResources();
int workspaceResId = partnerRes.getIdentifier(Partner.RES_DEFAULT_LAYOUT,
"xml", partner.getPackageName());
if (partner != null) {
int workspaceResId = partner.getXmlResId(RES_PARTNER_DEFAULT_LAYOUT);
if (workspaceResId != 0) {
loader = new DefaultLayoutParser(getContext(), widgetHolder,
mOpenHelper, partnerRes, workspaceResId);
mOpenHelper, partner.getResources(), workspaceResId);
}
}
}
-148
View File
@@ -1,148 +0,0 @@
/*
* Copyright (C) 2014 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 static com.android.launcher3.util.PackageManagerHelper.findSystemApk;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.Pair;
import java.io.File;
/**
* Utilities to discover and interact with partner customizations. There can
* only be one set of customizations on a device, and it must be bundled with
* the system.
*/
public class Partner {
static final String TAG = "Launcher.Partner";
/** Marker action used to discover partner */
private static final String
ACTION_PARTNER_CUSTOMIZATION = "com.android.launcher3.action.PARTNER_CUSTOMIZATION";
public static final String RES_FOLDER = "partner_folder";
public static final String RES_WALLPAPERS = "partner_wallpapers";
public static final String RES_DEFAULT_LAYOUT = "partner_default_layout";
public static final String RES_DEFAULT_WALLPAPER_HIDDEN = "default_wallpapper_hidden";
public static final String RES_SYSTEM_WALLPAPER_DIR = "system_wallpaper_directory";
public static final String RES_REQUIRE_FIRST_RUN_FLOW = "requires_first_run_flow";
/** These resources are used to override the device profile */
public static final String RES_GRID_NUM_ROWS = "grid_num_rows";
public static final String RES_GRID_NUM_COLUMNS = "grid_num_columns";
public static final String RES_GRID_ICON_SIZE_DP = "grid_icon_size_dp";
/**
* Find and return partner details, or {@code null} if none exists.
*/
public static synchronized Partner get(PackageManager pm) {
Pair<String, Resources> apkInfo = findSystemApk(ACTION_PARTNER_CUSTOMIZATION, pm);
return apkInfo != null ? new Partner(apkInfo.first, apkInfo.second) : null;
}
private final String mPackageName;
private final Resources mResources;
private Partner(String packageName, Resources res) {
mPackageName = packageName;
mResources = res;
}
public String getPackageName() {
return mPackageName;
}
public Resources getResources() {
return mResources;
}
public boolean hasDefaultLayout() {
int defaultLayout = getResources().getIdentifier(Partner.RES_DEFAULT_LAYOUT,
"xml", getPackageName());
return defaultLayout != 0;
}
public boolean hasFolder() {
int folder = getResources().getIdentifier(Partner.RES_FOLDER,
"xml", getPackageName());
return folder != 0;
}
public boolean hideDefaultWallpaper() {
int resId = getResources().getIdentifier(RES_DEFAULT_WALLPAPER_HIDDEN, "bool",
getPackageName());
return resId != 0 && getResources().getBoolean(resId);
}
public File getWallpaperDirectory() {
int resId = getResources().getIdentifier(RES_SYSTEM_WALLPAPER_DIR, "string",
getPackageName());
return (resId != 0) ? new File(getResources().getString(resId)) : null;
}
public boolean requiresFirstRunFlow() {
int resId = getResources().getIdentifier(RES_REQUIRE_FIRST_RUN_FLOW, "bool",
getPackageName());
return resId != 0 && getResources().getBoolean(resId);
}
public void applyInvariantDeviceProfileOverrides(InvariantDeviceProfile inv, DisplayMetrics dm) {
int numRows = -1;
int numColumns = -1;
float iconSize = -1;
try {
int resId = getResources().getIdentifier(RES_GRID_NUM_ROWS,
"integer", getPackageName());
if (resId > 0) {
numRows = getResources().getInteger(resId);
}
resId = getResources().getIdentifier(RES_GRID_NUM_COLUMNS,
"integer", getPackageName());
if (resId > 0) {
numColumns = getResources().getInteger(resId);
}
resId = getResources().getIdentifier(RES_GRID_ICON_SIZE_DP,
"dimen", getPackageName());
if (resId > 0) {
int px = getResources().getDimensionPixelSize(resId);
iconSize = Utilities.dpiFromPx((float) px, dm.densityDpi);
}
} catch (Resources.NotFoundException ex) {
Log.e(TAG, "Invalid Partner grid resource!", ex);
return;
}
if (numRows > 0 && numColumns > 0) {
inv.numRows = numRows;
inv.numColumns = numColumns;
}
if (iconSize > 0) {
inv.iconSize[InvariantDeviceProfile.INDEX_DEFAULT] = iconSize;
}
}
}
@@ -89,14 +89,6 @@ public final class FeatureFlags {
getDebugFlag("ENABLE_FLOATING_SEARCH_BAR", false,
"Keep All Apps search bar at the bottom (but above keyboard if open)");
public static final BooleanFlag ENABLE_QUICK_LAUNCH_V2 = new DeviceFlag(
"ENABLE_QUICK_LAUNCH_V2", false, "Use quick launch v2 "
+ "behavior. Quick search and quick launch v1 would be unavailable if this is enabled");
public static final BooleanFlag GBOARD_UPDATE_ENTER_KEY = new DeviceFlag(
"GBOARD_UPDATE_ENTER_KEY", false, "Update gBoard enter key "
+ "icon dynamically based on top search content for Quick Launch V2");
public static final BooleanFlag ENABLE_HIDE_HEADER = new DeviceFlag("ENABLE_HIDE_HEADER",
true, "Hide header on keyboard before typing in all apps");
@@ -374,6 +366,11 @@ public final class FeatureFlags {
"Enable the ability to tap a staged app during split select to launch it in full screen"
);
public static final BooleanFlag ENABLE_FORCED_MONO_ICON = getDebugFlag(
"ENABLE_FORCED_MONO_ICON", false,
"Enable the ability to generate monochromatic icons, if it is not provided by the app"
);
public static void initialize(Context context) {
synchronized (sDebugFlags) {
for (DebugFlag flag : sDebugFlags) {
@@ -74,7 +74,7 @@ public abstract class BaseItemDragListener implements View.OnDragListener, DragS
}
@Override
public boolean onActivityReady(Launcher launcher, boolean alreadyOnHome) {
public boolean init(Launcher launcher, boolean alreadyOnHome) {
AbstractFloatingView.closeAllOpenViews(launcher, alreadyOnHome);
launcher.getStateManager().goToState(NORMAL, alreadyOnHome /* animated */);
launcher.getDragLayer().setOnDragListener(this);
@@ -72,8 +72,8 @@ public class PinItemDragListener extends BaseItemDragListener {
}
@Override
public boolean onActivityReady(Launcher launcher, boolean alreadyOnHome) {
super.onActivityReady(launcher, alreadyOnHome);
public boolean init(Launcher launcher, boolean alreadyOnHome) {
super.init(launcher, alreadyOnHome);
if (!alreadyOnHome) {
launcher.useFadeOutAnimationForLauncherStart(mCancelSignal);
}
@@ -16,7 +16,10 @@
package com.android.launcher3.icons;
import static com.android.launcher3.config.FeatureFlags.ENABLE_FORCED_MONO_ICON;
import android.content.Context;
import android.graphics.drawable.Drawable;
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.graphics.IconShape;
@@ -68,6 +71,8 @@ public class LauncherIcons extends BaseIconFactory implements AutoCloseable {
private LauncherIcons next;
private MonochromeIconFactory mMonochromeIconFactory;
protected LauncherIcons(Context context, int fillResIconDpi, int iconBitmapSize, int poolId) {
super(context, fillResIconDpi, iconBitmapSize, IconShape.getShape().enableShapeDetection());
mMonoIconEnabled = Themes.isThemedIconEnabled(context);
@@ -90,6 +95,18 @@ public class LauncherIcons extends BaseIconFactory implements AutoCloseable {
}
}
@Override
protected Drawable getMonochromeDrawable(Drawable base) {
Drawable mono = super.getMonochromeDrawable(base);
if (mono != null || !ENABLE_FORCED_MONO_ICON.get()) {
return mono;
}
if (mMonochromeIconFactory == null) {
mMonochromeIconFactory = new MonochromeIconFactory(mIconBitmapSize);
}
return mMonochromeIconFactory.wrap(base);
}
@Override
public void close() {
recycle();
@@ -0,0 +1,180 @@
/*
* Copyright (C) 2022 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.icons;
import static android.graphics.Paint.FILTER_BITMAP_FLAG;
import android.annotation.TargetApi;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.BlendMode;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.drawable.AdaptiveIconDrawable;
import android.graphics.drawable.Drawable;
import android.os.Build;
import androidx.annotation.WorkerThread;
import com.android.launcher3.icons.BaseIconFactory.ClippedMonoDrawable;
import java.nio.ByteBuffer;
/**
* Utility class to generate monochrome icons version for a given drawable.
*/
@TargetApi(Build.VERSION_CODES.TIRAMISU)
public class MonochromeIconFactory extends Drawable {
private final Bitmap mFlatBitmap;
private final Canvas mFlatCanvas;
private final Paint mCopyPaint;
private final Bitmap mAlphaBitmap;
private final Canvas mAlphaCanvas;
private final byte[] mPixels;
private final int mBitmapSize;
private final int mEdgePixelLength;
private final Paint mDrawPaint;
private final Rect mSrcRect;
MonochromeIconFactory(int iconBitmapSize) {
float extraFactor = AdaptiveIconDrawable.getExtraInsetFraction();
float viewPortScale = 1 / (1 + 2 * extraFactor);
mBitmapSize = Math.round(iconBitmapSize * 2 * viewPortScale);
mPixels = new byte[mBitmapSize * mBitmapSize];
mEdgePixelLength = mBitmapSize * (mBitmapSize - iconBitmapSize) / 2;
mFlatBitmap = Bitmap.createBitmap(mBitmapSize, mBitmapSize, Config.ARGB_8888);
mFlatCanvas = new Canvas(mFlatBitmap);
mAlphaBitmap = Bitmap.createBitmap(mBitmapSize, mBitmapSize, Config.ALPHA_8);
mAlphaCanvas = new Canvas(mAlphaBitmap);
mDrawPaint = new Paint(FILTER_BITMAP_FLAG);
mDrawPaint.setColor(Color.WHITE);
mSrcRect = new Rect(0, 0, mBitmapSize, mBitmapSize);
mCopyPaint = new Paint(FILTER_BITMAP_FLAG);
mCopyPaint.setBlendMode(BlendMode.SRC);
// Crate a color matrix which converts the icon to grayscale and then uses the average
// of RGB components as the alpha component.
ColorMatrix satMatrix = new ColorMatrix();
satMatrix.setSaturation(0);
float[] vals = satMatrix.getArray();
vals[15] = vals[16] = vals[17] = .3333f;
vals[18] = vals[19] = 0;
mCopyPaint.setColorFilter(new ColorMatrixColorFilter(vals));
}
private void drawDrawable(Drawable drawable) {
if (drawable != null) {
drawable.setBounds(0, 0, mBitmapSize, mBitmapSize);
drawable.draw(mFlatCanvas);
}
}
/**
* Creates a monochrome version of the provided drawable
*/
@WorkerThread
public Drawable wrap(Drawable icon) {
if (icon instanceof AdaptiveIconDrawable) {
AdaptiveIconDrawable aid = (AdaptiveIconDrawable) icon;
mFlatCanvas.drawColor(Color.BLACK);
drawDrawable(aid.getBackground());
drawDrawable(aid.getForeground());
generateMono();
return new ClippedMonoDrawable(this);
} else {
mFlatCanvas.drawColor(Color.WHITE);
drawDrawable(icon);
generateMono();
return this;
}
}
@WorkerThread
private void generateMono() {
mAlphaCanvas.drawBitmap(mFlatBitmap, 0, 0, mCopyPaint);
// Scale the end points:
ByteBuffer buffer = ByteBuffer.wrap(mPixels);
buffer.rewind();
mAlphaBitmap.copyPixelsToBuffer(buffer);
int min = 0xFF;
int max = 0;
for (byte b : mPixels) {
min = Math.min(min, b & 0xFF);
max = Math.max(max, b & 0xFF);
}
if (min < max) {
// rescale pixels to increase contrast
float range = max - min;
// In order to check if the colors should be flipped, we just take the average color
// of top and bottom edge which should correspond to be background color. If the edge
// colors have more opacity, we flip the colors;
int sum = 0;
for (int i = 0; i < mEdgePixelLength; i++) {
sum += (mPixels[i] & 0xFF);
sum += (mPixels[mPixels.length - 1 - i] & 0xFF);
}
float edgeAverage = sum / (mEdgePixelLength * 2f);
float edgeMapped = (edgeAverage - min) / range;
boolean flipColor = edgeMapped > .5f;
for (int i = 0; i < mPixels.length; i++) {
int p = mPixels[i] & 0xFF;
int p2 = Math.round((p - min) * 0xFF / range);
mPixels[i] = flipColor ? (byte) (255 - p2) : (byte) (p2);
}
buffer.rewind();
mAlphaBitmap.copyPixelsFromBuffer(buffer);
}
}
@Override
public void draw(Canvas canvas) {
canvas.drawBitmap(mAlphaBitmap, mSrcRect, getBounds(), mDrawPaint);
}
@Override
public int getOpacity() {
return PixelFormat.TRANSLUCENT;
}
@Override
public void setAlpha(int i) {
mDrawPaint.setAlpha(i);
}
@Override
public void setColorFilter(ColorFilter colorFilter) {
mDrawPaint.setColorFilter(colorFilter);
}
}
@@ -20,6 +20,8 @@ import androidx.annotation.Nullable;
import com.android.launcher3.BaseActivity;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.concurrent.CopyOnWriteArrayList;
/**
@@ -28,15 +30,8 @@ import java.util.concurrent.CopyOnWriteArrayList;
*/
public final class ActivityTracker<T extends BaseActivity> {
public static final int TYPE_INIT = 0;
public static final int TYPE_DESTROY = 1;
public static final int TYPE_BOTH = 2;
private WeakReference<T> mCurrentActivity = new WeakReference<>(null);
private CopyOnWriteArrayList<SchedulerCallback<T>> mActivityReadyCallbacks =
new CopyOnWriteArrayList<>();
private CopyOnWriteArrayList<SchedulerCallback<T>> mActivityDestroyedCallbacks =
new CopyOnWriteArrayList<>();
private CopyOnWriteArrayList<SchedulerCallback<T>> mCallbacks = new CopyOnWriteArrayList<>();
@Nullable
public <R extends T> R getCreatedActivity() {
@@ -47,74 +42,32 @@ public final class ActivityTracker<T extends BaseActivity> {
if (mCurrentActivity.get() == activity) {
mCurrentActivity.clear();
}
for (SchedulerCallback<T> cb : mActivityDestroyedCallbacks) {
cb.onActivityDestroyed();
unregisterCallback(cb, TYPE_DESTROY);
}
}
/** Registers an activity create callback. */
/**
* Call {@link SchedulerCallback#init(BaseActivity, boolean)} when the
* activity is ready. If the activity is already created, this is called immediately.
*
* The tracker maintains a strong ref to the callback, so it is up to the caller to return
* {@code false} in the callback OR to unregister the callback explicitly.
*
* @param callback The callback to call init() on when the activity is ready.
*/
public void registerCallback(SchedulerCallback<T> callback) {
registerCallback(callback, TYPE_INIT);
}
/**
* Call {@link SchedulerCallback#onActivityReady(BaseActivity, boolean)} when the
* activity is ready and/or {@link SchedulerCallback#onActivityDestroyed()} when the activity
* is destroyed.
*
* If type is {@link ActivityTracker#TYPE_INIT} TYPE_INIT or
* {@link ActivityTracker#TYPE_BOTH} and the activity is already created, this
* {@link SchedulerCallback#onActivityReady(BaseActivity, boolean)} is called immediately.
*
* If type is {@link ActivityTracker#TYPE_DESTROY} or
* {@link ActivityTracker#TYPE_BOTH} and the activity is already destroyed,
* {@link SchedulerCallback#onActivityDestroyed()} is called immediately.
*
* The tracker maintains a strong ref to the callbacks, so it is up to the caller to return
* {@code false} in {@link SchedulerCallback#onActivityReady(BaseActivity, boolean)} OR to
* unregister the callback explicitly.
*
* @param callback The callback to call init() or cleanUp() on when the activity is ready or
* destroyed.
* @param type whether to use this callback on activity create, destroy or both.
*/
public void registerCallback(SchedulerCallback<T> callback, int type) {
T activity = mCurrentActivity.get();
if (type == TYPE_INIT || type == TYPE_BOTH) {
mActivityReadyCallbacks.add(callback);
if (activity != null) {
if (!callback.onActivityReady(activity, activity.isStarted())) {
unregisterCallback(callback, TYPE_INIT);
}
mCallbacks.add(callback);
if (activity != null) {
if (!callback.init(activity, activity.isStarted())) {
unregisterCallback(callback);
}
}
if (type == TYPE_DESTROY || type == TYPE_BOTH) {
mActivityDestroyedCallbacks.add(callback);
if (activity == null) {
callback.onActivityDestroyed();
unregisterCallback(callback, TYPE_DESTROY);
}
}
}
/**
* Unregisters a registered activity create callback.
*/
public void unregisterCallback(SchedulerCallback<T> callback) {
unregisterCallback(callback, TYPE_INIT);
}
/**
* Unregisters a registered callback.
*/
public void unregisterCallback(SchedulerCallback<T> callback, int type) {
if (type == TYPE_INIT || type == TYPE_BOTH) {
mActivityReadyCallbacks.remove(callback);
}
if (type == TYPE_DESTROY || type == TYPE_BOTH) {
mActivityDestroyedCallbacks.remove(callback);
}
public void unregisterCallback(SchedulerCallback<T> callback) {
mCallbacks.remove(callback);
}
public boolean handleCreate(T activity) {
@@ -128,8 +81,8 @@ public final class ActivityTracker<T extends BaseActivity> {
private boolean handleIntent(T activity, boolean alreadyOnHome) {
boolean handled = false;
for (SchedulerCallback<T> cb : mActivityReadyCallbacks) {
if (!cb.onActivityReady(activity, alreadyOnHome)) {
for (SchedulerCallback<T> cb : mCallbacks) {
if (!cb.init(activity, alreadyOnHome)) {
// Callback doesn't want any more updates
unregisterCallback(cb);
}
@@ -145,11 +98,6 @@ public final class ActivityTracker<T extends BaseActivity> {
* @param alreadyOnHome Whether the activity is already started.
* @return Whether to continue receiving callbacks (i.e. if the activity is recreated).
*/
boolean onActivityReady(T activity, boolean alreadyOnHome);
/**
* Called then the activity gets destroyed.
*/
default void onActivityDestroyed() { }
boolean init(T activity, boolean alreadyOnHome);
}
}
@@ -131,7 +131,10 @@ public class DisplayController implements ComponentCallbacks, SafeCloseable {
* Returns whether taskbar is transient.
*/
public static boolean isTransientTaskbar(Context context) {
if (FORCE_PERSISTENT_TASKBAR.get()) {
// TODO(b/258604917): When running in test harness, use !sTransientTaskbarStatusForTests
// once tests are updated to expect new persistent behavior such as not allowing long press
// to stash.
if (!Utilities.IS_RUNNING_IN_TEST_HARNESS && FORCE_PERSISTENT_TASKBAR.get()) {
return false;
}
return getNavigationMode(context) == NavigationMode.NO_BUTTON
@@ -16,8 +16,6 @@
package com.android.launcher3.util;
import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
import android.app.AppOpsManager;
import android.content.ActivityNotFoundException;
import android.content.ComponentName;
@@ -31,7 +29,6 @@ import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
import android.content.res.Resources;
import android.graphics.Rect;
import android.net.Uri;
import android.os.Build;
@@ -40,7 +37,6 @@ import android.os.PatternMatcher;
import android.os.UserHandle;
import android.text.TextUtils;
import android.util.Log;
import android.util.Pair;
import android.widget.Toast;
import androidx.annotation.NonNull;
@@ -295,25 +291,6 @@ public class PackageManagerHelper {
}
}
/**
* Finds a system apk which had a broadcast receiver listening to a particular action.
* @param action intent action used to find the apk
* @return a pair of apk package name and the resources.
*/
public static Pair<String, Resources> findSystemApk(String action, PackageManager pm) {
final Intent intent = new Intent(action);
for (ResolveInfo info : pm.queryBroadcastReceivers(intent, MATCH_SYSTEM_ONLY)) {
final String packageName = info.activityInfo.packageName;
try {
final Resources res = pm.getResourcesForApplication(packageName);
return Pair.create(packageName, res);
} catch (NameNotFoundException e) {
Log.w(TAG, "Failed to find resources for " + packageName);
}
}
return null;
}
/**
* Returns true if the intent is a valid launch intent for a launcher activity of an app.
* This is used to identify shortcuts which are different from the ones exposed by the
+116
View File
@@ -0,0 +1,116 @@
/*
* Copyright (C) 2014 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.util;
import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
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.util.Log;
import android.util.Pair;
/**
* Utilities to discover and interact with partner customizations. There can
* only be one set of customizations on a device, and it must be bundled with
* the system.
*/
public class Partner {
static final String TAG = "Launcher.Partner";
/** Marker action used to discover partner */
private static final String
ACTION_PARTNER_CUSTOMIZATION = "com.android.launcher3.action.PARTNER_CUSTOMIZATION";
/**
* Find and return partner details, or {@code null} if none exists.
*/
public static Partner get(PackageManager pm) {
return get(pm, ACTION_PARTNER_CUSTOMIZATION);
}
/**
* Find and return partner details, or {@code null} if none exists.
*/
public static Partner get(PackageManager pm, String action) {
Pair<String, Resources> apkInfo = findSystemApk(action, pm);
return apkInfo != null ? new Partner(apkInfo.first, apkInfo.second) : null;
}
private final String mPackageName;
private final Resources mResources;
private Partner(String packageName, Resources res) {
mPackageName = packageName;
mResources = res;
}
public String getPackageName() {
return mPackageName;
}
public Resources getResources() {
return mResources;
}
/**
* Returns the xml resource Id for the provided name, or 0 is the resource is not found
*/
public int getXmlResId(String layoutName) {
return getResources().getIdentifier(layoutName, "xml", getPackageName());
}
/**
* Returns the integer resource value for the provided resource name,
* or default value if the resource name is not present
*/
public int getIntValue(String resName, int defaultValue) {
int resId = getResources().getIdentifier(resName, "integer", getPackageName());
return resId > 0 ? getResources().getInteger(resId) : defaultValue;
}
/**
* Returns the dimension value for the provided resource name,
* or default value if the resource name is not present
*/
public float getDimenValue(String resName, int defaultValue) {
int resId = getResources().getIdentifier(resName, "dimen", getPackageName());
return resId > 0 ? getResources().getDimension(resId) : defaultValue;
}
/**
* Finds a system apk which had a broadcast receiver listening to a particular action.
* @param action intent action used to find the apk
* @return a pair of apk package name and the resources.
*/
private static Pair<String, Resources> findSystemApk(String action, PackageManager pm) {
final Intent intent = new Intent(action);
for (ResolveInfo info : pm.queryBroadcastReceivers(intent, MATCH_SYSTEM_ONLY)) {
final String packageName = info.activityInfo.packageName;
try {
final Resources res = pm.getResourcesForApplication(packageName);
return Pair.create(packageName, res);
} catch (NameNotFoundException e) {
Log.w(TAG, "Failed to find resources for " + packageName);
}
}
return null;
}
}
@@ -55,7 +55,7 @@ public class SearchResultFromQsb {
}
/** Find the web suggestion from search suggestion's title text */
public void findWebSuggest(String text) {
public void verifyWebSuggestIsPresent(String text) {
ArrayList<UiObject2> goldenGateResults =
new ArrayList<>(mLauncher.waitForObjectsInContainer(
mLauncher.waitForSystemLauncherObject(SEARCH_CONTAINER_RES_ID),