blob: 43a3844784edf73d14bdadac40d83d404133047a [file] [log] [blame]
/*
* 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 android.packageinstaller.nopermission.cts
import android.app.PendingIntent
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.content.pm.PackageManager;
import android.content.pm.PackageInstaller
import android.content.pm.PackageInstaller.EXTRA_STATUS
import android.content.pm.PackageInstaller.STATUS_FAILURE_INVALID
import android.os.Build
import android.platform.test.annotations.AppModeFull
import androidx.test.InstrumentationRegistry
import androidx.test.filters.MediumTest
import androidx.test.runner.AndroidJUnit4
import android.support.test.uiautomator.By
import android.support.test.uiautomator.UiDevice
import android.support.test.uiautomator.Until
import androidx.core.content.FileProvider
import org.junit.After
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.model.Statement
import org.junit.runner.Description
import org.junit.Rule
import org.junit.rules.TestRule
import org.junit.AssumptionViolatedException
import java.io.File
import java.lang.IllegalArgumentException
private const val TEST_APK_NAME = "CtsEmptyTestApp.apk"
private const val TEST_APK_PACKAGE_NAME = "android.packageinstaller.emptytestapp.cts"
private const val TEST_APK_EXTERNAL_LOCATION = "/data/local/tmp/cts/nopermission"
private const val CONTENT_AUTHORITY = "android.packageinstaller.nopermission.cts.fileprovider"
private const val PACKAGE_INSTALLER_PACKAGE_NAME = "com.android.packageinstaller"
private const val INSTALL_CONFIRM_TEXT_ID = "install_confirm_question"
private const val WM_DISMISS_KEYGUARD_COMMAND = "wm dismiss-keyguard"
private const val ACTION = "NoPermissionTests.install_cb"
private const val WAIT_FOR_UI_TIMEOUT = 5000L
@RunWith(AndroidJUnit4::class)
@MediumTest
@AppModeFull
class NoPermissionTests {
private var context = InstrumentationRegistry.getTargetContext()
private var pm = context.packageManager
private var packageName = context.packageName
private var apkFile = File(context.filesDir, TEST_APK_NAME)
private var uiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
private var isWatch: Boolean = pm.hasSystemFeature(PackageManager.FEATURE_WATCH)
private val receiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
val status = intent.getIntExtra(EXTRA_STATUS, STATUS_FAILURE_INVALID)
if (status == PackageInstaller.STATUS_PENDING_USER_ACTION) {
val activityIntent = intent.getParcelableExtra<Intent>(Intent.EXTRA_INTENT)
activityIntent!!.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
context.startActivity(activityIntent)
}
}
}
@get:Rule
val testRule: TestRule = object :TestRule {
override fun apply(base: Statement, description: Description?)
= NewStatement(base)
inner class NewStatement(private val base: Statement) : Statement() {
@Throws(Throwable::class)
override fun evaluate() {
if (isWatch) {
throw AssumptionViolatedException("Install/uninstall feature is not supported on WearOs");
}
base.evaluate()
}
}
}
@Before
fun wakeUpScreen() {
if (!uiDevice.isScreenOn) {
uiDevice.wakeUp()
}
uiDevice.executeShellCommand(WM_DISMISS_KEYGUARD_COMMAND)
}
@Before
fun copyTestApk() {
File(TEST_APK_EXTERNAL_LOCATION, TEST_APK_NAME).copyTo(target = apkFile, overwrite = true)
}
@Before
fun registerInstallResultReceiver() {
context.registerReceiver(receiver, IntentFilter(ACTION),
Context.RECEIVER_EXPORTED_UNAUDITED)
}
@Before
fun waitForUIIdle() {
uiDevice.waitForIdle()
}
private fun launchPackageInstallerViaIntent() {
val intent = Intent(Intent.ACTION_INSTALL_PACKAGE)
intent.data = FileProvider.getUriForFile(context, CONTENT_AUTHORITY, apkFile)
intent.flags = Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_ACTIVITY_NEW_TASK
context.startActivity(intent)
}
private fun launchPackageInstallerViaSession() {
val pi = pm.packageInstaller
// Create session
val sessionId = pi.createSession(PackageInstaller.SessionParams(
PackageInstaller.SessionParams.MODE_FULL_INSTALL))
val session = pi.openSession(sessionId)!!
// Write data to session
File(TEST_APK_EXTERNAL_LOCATION, TEST_APK_NAME).inputStream().use { fileOnDisk ->
session.openWrite(TEST_APK_NAME, 0, -1).use { sessionFile ->
fileOnDisk.copyTo(sessionFile)
}
}
// Commit session
val pendingIntent = PendingIntent.getBroadcast(context, 0, Intent(ACTION),
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE)
session.commit(pendingIntent.intentSender)
}
private fun assertInstallSucceeded(errorMessage: String) {
val selector = By.res(PACKAGE_INSTALLER_PACKAGE_NAME, INSTALL_CONFIRM_TEXT_ID)
assertTrue(errorMessage, uiDevice.wait(Until.hasObject(selector), WAIT_FOR_UI_TIMEOUT))
uiDevice.pressBack()
}
private fun assertInstallFailed(errorMessage: String) {
val selector = By.res(PACKAGE_INSTALLER_PACKAGE_NAME, INSTALL_CONFIRM_TEXT_ID)
assertFalse(errorMessage, uiDevice.wait(Until.hasObject(selector), WAIT_FOR_UI_TIMEOUT))
uiDevice.pressBack()
}
@Test
fun noPermissionsTestIntent() {
launchPackageInstallerViaIntent()
if (pm.getPackageInfo(packageName, 0).applicationInfo.targetSdkVersion
>= Build.VERSION_CODES.O) {
assertInstallFailed("Package Installer UI should not appear")
} else {
assertInstallSucceeded("Package Installer UI should appear")
}
}
@Test
fun noPermissionsTestSession() {
launchPackageInstallerViaSession()
if (pm.getPackageInfo(packageName, 0).applicationInfo.targetSdkVersion
>= Build.VERSION_CODES.O) {
assertInstallFailed("Package Installer UI should not appear")
} else {
assertInstallSucceeded("Package Installer UI should appear")
}
}
@After
fun unregisterInstallResultReceiver() {
try {
context.unregisterReceiver(receiver)
} catch (ignored: IllegalArgumentException) {
}
}
@After
fun uninstallTestPackage() {
uiDevice.executeShellCommand("pm uninstall $TEST_APK_PACKAGE_NAME")
}
}