| /** |
| * 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; |
| |
| import static org.junit.Assert.assertEquals; |
| import static org.junit.Assert.assertFalse; |
| |
| import android.app.prediction.AppPredictor; |
| import android.app.prediction.AppTarget; |
| import android.app.prediction.AppTargetId; |
| import android.content.ComponentName; |
| import android.content.pm.LauncherActivityInfo; |
| import android.os.Process; |
| import android.view.View; |
| |
| import androidx.test.filters.LargeTest; |
| import androidx.test.runner.AndroidJUnit4; |
| |
| import com.android.launcher3.BubbleTextView; |
| import com.android.launcher3.Launcher; |
| import com.android.launcher3.appprediction.PredictionRowView; |
| import com.android.launcher3.appprediction.PredictionUiStateManager; |
| import com.android.launcher3.appprediction.PredictionUiStateManager.Client; |
| import com.android.launcher3.compat.LauncherAppsCompat; |
| import com.android.launcher3.model.AppLaunchTracker; |
| |
| import org.junit.After; |
| import org.junit.Before; |
| import org.junit.Test; |
| import org.junit.runner.RunWith; |
| |
| import java.util.ArrayList; |
| import java.util.List; |
| |
| @LargeTest |
| @RunWith(AndroidJUnit4.class) |
| public class AppPredictionsUITests extends AbstractQuickStepTest { |
| |
| private LauncherActivityInfo mSampleApp1; |
| private LauncherActivityInfo mSampleApp2; |
| private LauncherActivityInfo mSampleApp3; |
| |
| private AppPredictor.Callback mCallback; |
| |
| @Before |
| public void setUp() throws Exception { |
| super.setUp(); |
| |
| List<LauncherActivityInfo> activities = LauncherAppsCompat.getInstance(mTargetContext) |
| .getActivityList(null, Process.myUserHandle()); |
| mSampleApp1 = activities.get(0); |
| mSampleApp2 = activities.get(1); |
| mSampleApp3 = activities.get(2); |
| |
| // Disable app tracker |
| AppLaunchTracker.INSTANCE.initializeForTesting(new AppLaunchTracker()); |
| PredictionUiStateManager.INSTANCE.initializeForTesting(null); |
| |
| mCallback = PredictionUiStateManager.INSTANCE.get(mTargetContext).appPredictorCallback( |
| Client.HOME); |
| |
| mDevice.setOrientationNatural(); |
| } |
| |
| @After |
| public void tearDown() throws Throwable { |
| AppLaunchTracker.INSTANCE.initializeForTesting(null); |
| PredictionUiStateManager.INSTANCE.initializeForTesting(null); |
| mDevice.unfreezeRotation(); |
| } |
| |
| /** |
| * Test that prediction UI is updated as soon as we get predictions from the system |
| */ |
| @Test |
| public void testPredictionExistsInAllApps() { |
| mActivityMonitor.startLauncher(); |
| mLauncher.pressHome().switchToAllApps(); |
| |
| // Dispatch an update |
| sendPredictionUpdate(mSampleApp1, mSampleApp2); |
| // The first update should apply immediately. |
| waitForLauncherCondition("Predictions were not updated in loading state", |
| launcher -> getPredictedApp(launcher).size() == 2); |
| } |
| |
| /** |
| * Test that prediction update is deferred if it is already visible |
| */ |
| @Test |
| public void testPredictionsDeferredUntilHome() { |
| mActivityMonitor.startLauncher(); |
| sendPredictionUpdate(mSampleApp1, mSampleApp2); |
| mLauncher.pressHome().switchToAllApps(); |
| waitForLauncherCondition("Predictions were not updated in loading state", |
| launcher -> getPredictedApp(launcher).size() == 2); |
| |
| // Update predictions while all-apps is visible |
| sendPredictionUpdate(mSampleApp1, mSampleApp2, mSampleApp3); |
| assertEquals(2, getFromLauncher(this::getPredictedApp).size()); |
| |
| // Go home and go back to all-apps |
| mLauncher.pressHome().switchToAllApps(); |
| assertEquals(3, getFromLauncher(this::getPredictedApp).size()); |
| } |
| |
| @Test |
| public void testPredictionsDisabled() { |
| mActivityMonitor.startLauncher(); |
| sendPredictionUpdate(); |
| mLauncher.pressHome().switchToAllApps(); |
| |
| waitForLauncherCondition("Predictions were not updated in loading state", |
| launcher -> launcher.getAppsView().getFloatingHeaderView() |
| .findFixedRowByType(PredictionRowView.class).getVisibility() == View.GONE); |
| assertFalse(PredictionUiStateManager.INSTANCE.get(mTargetContext) |
| .getCurrentState().isEnabled); |
| } |
| |
| public ArrayList<BubbleTextView> getPredictedApp(Launcher launcher) { |
| PredictionRowView container = launcher.getAppsView().getFloatingHeaderView() |
| .findFixedRowByType(PredictionRowView.class); |
| |
| ArrayList<BubbleTextView> predictedAppViews = new ArrayList<>(); |
| for (int i = 0; i < container.getChildCount(); i++) { |
| View view = container.getChildAt(i); |
| if (view instanceof BubbleTextView && view.getVisibility() == View.VISIBLE) { |
| predictedAppViews.add((BubbleTextView) view); |
| } |
| } |
| return predictedAppViews; |
| } |
| |
| private void sendPredictionUpdate(LauncherActivityInfo... activities) { |
| getOnUiThread(() -> { |
| List<AppTarget> targets = new ArrayList<>(activities.length); |
| for (LauncherActivityInfo info : activities) { |
| ComponentName cn = info.getComponentName(); |
| AppTarget target = |
| new AppTarget.Builder(new AppTargetId("app:" + cn), cn.getPackageName(), info.getUser()) |
| .setClassName(cn.getClassName()) |
| .build(); |
| targets.add(target); |
| } |
| mCallback.onTargetsAvailable(targets); |
| return null; |
| }); |
| } |
| } |