blob: 8e5aa9a0e02daae7b4657e4b5e0e8c417d9968a6 [file] [log] [blame]
/*
* Copyright (C) 2021 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.tests.loadingprogress.device;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import android.annotation.NonNull;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.LauncherActivityInfo;
import android.content.pm.LauncherApps;
import android.content.pm.PackageManager;
import android.os.ConditionVariable;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Process;
import android.os.UserHandle;
import androidx.test.filters.LargeTest;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;
import java.util.function.Predicate;
/**
* Device-side test, launched by the host-side test only and should not be called directly.
*/
@RunWith(AndroidJUnit4.class)
@LargeTest
public class LoadingProgressTest {
private static final String TEST_PACKAGE_NAME = "com.android.tests.loadingprogress.app";
private static final String REGISTER_APP_NAME = "com.android.tests.loadingprogress.registerapp";
protected Context mContext;
private PackageManager mPackageManager;
private UserHandle mUser;
private LauncherApps mLauncherApps;
private static final int WAIT_TIMEOUT_MILLIS = 2000; /* 2 second */
private ConditionVariable mCalled = new ConditionVariable();
private final HandlerThread mCallbackThread = new HandlerThread("callback");
private LauncherAppsCallback mCallback;
@Before
public void setUp() {
mContext = InstrumentationRegistry.getInstrumentation().getContext();
mPackageManager = mContext.getPackageManager();
assertNotNull(mPackageManager);
mUser = Process.myUserHandle();
mLauncherApps = mContext.getSystemService(LauncherApps.class);
mCallbackThread.start();
}
@After
public void tearDown() {
mCallbackThread.quit();
if (mCallback != null) {
mLauncherApps.unregisterCallback(mCallback);
}
}
@Test
public void registerFirstLauncherAppsCallback() {
final Intent intent = mPackageManager.getLaunchIntentForPackage(REGISTER_APP_NAME);
assertNotNull(intent);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
mContext.startActivity(intent);
}
@Test
public void testGetPartialLoadingProgress() throws Exception {
// Package is installed but only partially streamed
checkLoadingProgress(loadingProgress -> loadingProgress < 1.0f && loadingProgress > 0);
}
@Test
public void testReadAllBytes() throws Exception {
ApplicationInfo appInfo = mLauncherApps.getApplicationInfo(
TEST_PACKAGE_NAME, /* flags= */ 0, mUser);
final String codePath = appInfo.sourceDir;
final String apkDir = codePath.substring(0, codePath.lastIndexOf('/'));
for (String apkName : new File(apkDir).list()) {
final String apkPath = apkDir + "/" + apkName;
assertTrue(new File(apkPath).exists());
byte[] apkContentBytes = Files.readAllBytes(Paths.get(apkPath));
assertNotNull(apkContentBytes);
assertTrue(apkContentBytes.length > 0);
}
}
@Test
public void testGetFullLoadingProgress() throws Exception {
// Package should be fully streamed now
checkLoadingProgress(loadingProgress -> (1 - loadingProgress) < 0.001f);
}
private void checkLoadingProgress(Predicate<Float> progressCondition) {
List<LauncherActivityInfo> activities =
mLauncherApps.getActivityList(TEST_PACKAGE_NAME, mUser);
boolean foundTestApp = false;
for (LauncherActivityInfo activity : activities) {
if (activity.getComponentName().getPackageName().equals(
TEST_PACKAGE_NAME)) {
foundTestApp = true;
final float progress = activity.getLoadingProgress();
assertTrue("progress <" + progress + "> does not meet requirement",
progressCondition.test(progress));
}
assertTrue(activity.getUser().equals(mUser));
}
assertTrue(foundTestApp);
}
@Test
public void testOnPackageLoadingProgressChangedCalledWithPartialLoaded() throws Exception {
mCalled.close();
mCallback = new LauncherAppsCallback(
loadingProgress -> loadingProgress < 1.0f && loadingProgress > 0);
mLauncherApps.registerCallback(mCallback, new Handler(mCallbackThread.getLooper()));
assertTrue(mCalled.block(WAIT_TIMEOUT_MILLIS));
}
@Test
public void testOnPackageLoadingProgressChangedCalledWithFullyLoaded() throws Exception {
mCalled.close();
mCallback = new LauncherAppsCallback(loadingProgress -> 1 - loadingProgress < 0.001);
mLauncherApps.registerCallback(mCallback, new Handler(mCallbackThread.getLooper()));
testReadAllBytes();
assertTrue(mCalled.block(WAIT_TIMEOUT_MILLIS));
}
class LauncherAppsCallback extends LauncherApps.Callback {
private final Predicate<Float> mCondition;
LauncherAppsCallback(Predicate<Float> progressCondition) {
mCondition = progressCondition;
}
@Override
public void onPackageRemoved(String packageName, UserHandle user) {
}
@Override
public void onPackageAdded(String packageName, UserHandle user) {
}
@Override
public void onPackageChanged(String packageName, UserHandle user) {
}
@Override
public void onPackagesAvailable(String[] packageNames, UserHandle user, boolean replacing) {
}
@Override
public void onPackagesUnavailable(String[] packageNames, UserHandle user,
boolean replacing) {
}
@Override
public void onPackageLoadingProgressChanged(@NonNull String packageName,
@NonNull UserHandle user, float progress) {
if (mCondition.test(progress)) {
// Only release when progress meets the expected condition
mCalled.open();
}
}
}
}