blob: 48a1b5d1da272f686417ba31325dcf8aabc497d2 [file] [log] [blame]
/*
* Copyright (C) 2016 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.cts.normalapp;
import static org.hamcrest.CoreMatchers.hasItems;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
import android.content.ActivityNotFoundException;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ResolveInfo;
import android.database.Cursor;
import android.net.Uri;
import android.provider.Settings.Secure;
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
import com.android.cts.util.TestResult;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.List;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.TimeUnit;
@RunWith(AndroidJUnit4.class)
public class ClientTest {
/** Action to start normal test activities */
private static final String ACTION_START_NORMAL_ACTIVITY =
"com.android.cts.ephemeraltest.START_NORMAL";
/** Action to start normal, exposed test activities */
private static final String ACTION_START_EXPOSED_ACTIVITY =
"com.android.cts.ephemeraltest.START_EXPOSED";
/** Action to start ephemeral test activities */
private static final String ACTION_START_EPHEMERAL_ACTIVITY =
"com.android.cts.ephemeraltest.START_EPHEMERAL";
/** Action to query for test activities */
private static final String ACTION_QUERY =
"com.android.cts.ephemeraltest.QUERY";
private static final String EXTRA_ACTIVITY_NAME =
"com.android.cts.ephemeraltest.EXTRA_ACTIVITY_NAME";
private static final String EXTRA_ACTIVITY_RESULT =
"com.android.cts.ephemeraltest.EXTRA_ACTIVITY_RESULT";
private BroadcastReceiver mReceiver;
private final SynchronousQueue<TestResult> mResultQueue = new SynchronousQueue<>();
@Before
public void setUp() throws Exception {
final IntentFilter filter =
new IntentFilter("com.android.cts.ephemeraltest.START_ACTIVITY");
filter.addCategory(Intent.CATEGORY_DEFAULT);
mReceiver = new ActivityBroadcastReceiver(mResultQueue);
InstrumentationRegistry.getContext()
.registerReceiver(mReceiver, filter, Context.RECEIVER_VISIBLE_TO_INSTANT_APPS);
}
@After
public void tearDown() throws Exception {
InstrumentationRegistry.getContext().unregisterReceiver(mReceiver);
}
@Test
public void testQuery() throws Exception {
// query activities without flags
{
final Intent queryIntent = new Intent(ACTION_QUERY);
final List<ResolveInfo> resolveInfo = InstrumentationRegistry.getContext()
.getPackageManager().queryIntentActivities(queryIntent, 0 /*flags*/);
if (resolveInfo == null || resolveInfo.size() == 0) {
fail("didn't resolve any intents");
}
assertThat(resolveInfo.size(), is(2));
assertThat(resolveInfo.get(0).activityInfo.packageName,
is("com.android.cts.normalapp"));
assertThat(resolveInfo.get(0).activityInfo.name,
is("com.android.cts.normalapp.ExposedActivity"));
assertThat(resolveInfo.get(0).isInstantAppAvailable,
is(false));
assertThat(resolveInfo.get(1).activityInfo.packageName,
is("com.android.cts.normalapp"));
assertThat(resolveInfo.get(1).activityInfo.name,
is("com.android.cts.normalapp.NormalActivity"));
assertThat(resolveInfo.get(1).isInstantAppAvailable,
is(false));
}
// query activities asking for ephemeral apps [we should only get normal apps]
{
final Intent queryIntent = new Intent(ACTION_QUERY);
final int MATCH_EPHEMERAL = 0x00800000;
final List<ResolveInfo> resolveInfo = InstrumentationRegistry.getContext()
.getPackageManager().queryIntentActivities(queryIntent, MATCH_EPHEMERAL);
if (resolveInfo == null || resolveInfo.size() == 0) {
fail("didn't resolve any intents");
}
assertThat(resolveInfo.size(), is(2));
assertThat(resolveInfo.get(0).activityInfo.packageName,
is("com.android.cts.normalapp"));
assertThat(resolveInfo.get(0).activityInfo.name,
is("com.android.cts.normalapp.ExposedActivity"));
assertThat(resolveInfo.get(0).isInstantAppAvailable,
is(false));
assertThat(resolveInfo.get(1).activityInfo.packageName,
is("com.android.cts.normalapp"));
assertThat(resolveInfo.get(1).activityInfo.name,
is("com.android.cts.normalapp.NormalActivity"));
assertThat(resolveInfo.get(1).isInstantAppAvailable,
is(false));
}
// query activities; directed package
{
final Intent queryIntent = new Intent(ACTION_QUERY);
queryIntent.setPackage("com.android.cts.ephemeralapp1");
final List<ResolveInfo> resolveInfo = InstrumentationRegistry.getContext()
.getPackageManager().queryIntentActivities(queryIntent, 0 /*flags*/);
assertThat(resolveInfo.size(), is(0));
}
// query activities; directed component
{
final Intent queryIntent = new Intent(ACTION_QUERY);
queryIntent.setComponent(
new ComponentName("com.android.cts.ephemeralapp1",
"com.android.cts.ephemeralapp1.EphemeralActivity"));
final List<ResolveInfo> resolveInfo = InstrumentationRegistry.getContext()
.getPackageManager().queryIntentActivities(queryIntent, 0 /*flags*/);
assertThat(resolveInfo.size(), is(0));
}
// query services without flags
{
final Intent queryIntent = new Intent(ACTION_QUERY);
final List<ResolveInfo> resolveInfo = InstrumentationRegistry.getContext()
.getPackageManager().queryIntentServices(queryIntent, 0 /*flags*/);
if (resolveInfo == null || resolveInfo.size() == 0) {
fail("didn't resolve any intents");
}
assertThat(resolveInfo.size(), is(2));
assertThat(resolveInfo.get(0).serviceInfo.packageName,
is("com.android.cts.normalapp"));
assertThat(resolveInfo.get(0).serviceInfo.name,
is("com.android.cts.normalapp.ExposedService"));
assertThat(resolveInfo.get(0).isInstantAppAvailable,
is(false));
assertThat(resolveInfo.get(1).serviceInfo.packageName,
is("com.android.cts.normalapp"));
assertThat(resolveInfo.get(1).serviceInfo.name,
is("com.android.cts.normalapp.NormalService"));
assertThat(resolveInfo.get(1).isInstantAppAvailable,
is(false));
}
// query services asking for ephemeral apps [we should only get normal apps]
{
final Intent queryIntent = new Intent(ACTION_QUERY);
final int MATCH_EPHEMERAL = 0x00800000;
final List<ResolveInfo> resolveInfo = InstrumentationRegistry.getContext()
.getPackageManager().queryIntentServices(queryIntent, MATCH_EPHEMERAL);
if (resolveInfo == null || resolveInfo.size() == 0) {
fail("didn't resolve any intents");
}
assertThat(resolveInfo.size(), is(2));
assertThat(resolveInfo.get(0).serviceInfo.packageName,
is("com.android.cts.normalapp"));
assertThat(resolveInfo.get(0).serviceInfo.name,
is("com.android.cts.normalapp.ExposedService"));
assertThat(resolveInfo.get(0).isInstantAppAvailable,
is(false));
assertThat(resolveInfo.get(1).serviceInfo.packageName,
is("com.android.cts.normalapp"));
assertThat(resolveInfo.get(1).serviceInfo.name,
is("com.android.cts.normalapp.NormalService"));
assertThat(resolveInfo.get(1).isInstantAppAvailable,
is(false));
}
// query services; directed package
{
final Intent queryIntent = new Intent(ACTION_QUERY);
queryIntent.setPackage("com.android.cts.ephemeralapp1");
final List<ResolveInfo> resolveInfo = InstrumentationRegistry.getContext()
.getPackageManager().queryIntentServices(queryIntent, 0 /*flags*/);
assertThat(resolveInfo.size(), is(0));
}
// query services; directed component
{
final Intent queryIntent = new Intent(ACTION_QUERY);
queryIntent.setComponent(
new ComponentName("com.android.cts.ephemeralapp1",
"com.android.cts.ephemeralapp1.EphemeralService"));
final List<ResolveInfo> resolveInfo = InstrumentationRegistry.getContext()
.getPackageManager().queryIntentServices(queryIntent, 0 /*flags*/);
assertThat(resolveInfo.size(), is(0));
}
// query content providers without flags
{
final Intent queryIntent = new Intent(ACTION_QUERY);
final List<ResolveInfo> resolveInfo = InstrumentationRegistry
.getContext().getPackageManager().queryIntentContentProviders(
queryIntent, 0 /*flags*/);
if (resolveInfo == null || resolveInfo.size() == 0) {
fail("didn't resolve any intents");
}
assertThat(resolveInfo.size(), is(2));
assertThat(resolveInfo.get(0).providerInfo.packageName,
is("com.android.cts.normalapp"));
assertThat(resolveInfo.get(0).providerInfo.name,
is("com.android.cts.normalapp.ExposedProvider"));
assertThat(resolveInfo.get(1).providerInfo.packageName,
is("com.android.cts.normalapp"));
assertThat(resolveInfo.get(1).providerInfo.name,
is("com.android.cts.normalapp.NormalProvider"));
assertThat(resolveInfo.get(1).isInstantAppAvailable,
is(false));
}
// query content providers asking for ephemeral apps [we should only get normal apps]
{
final Intent queryIntent = new Intent(ACTION_QUERY);
final int MATCH_EPHEMERAL = 0x00800000;
final List<ResolveInfo> resolveInfo = InstrumentationRegistry.getContext()
.getPackageManager().queryIntentContentProviders(
queryIntent, MATCH_EPHEMERAL);
if (resolveInfo == null || resolveInfo.size() == 0) {
fail("didn't resolve any intents");
}
assertThat(resolveInfo.size(), is(2));
assertThat(resolveInfo.get(0).providerInfo.packageName,
is("com.android.cts.normalapp"));
assertThat(resolveInfo.get(0).providerInfo.name,
is("com.android.cts.normalapp.ExposedProvider"));
assertThat(resolveInfo.get(1).providerInfo.packageName,
is("com.android.cts.normalapp"));
assertThat(resolveInfo.get(1).providerInfo.name,
is("com.android.cts.normalapp.NormalProvider"));
assertThat(resolveInfo.get(1).isInstantAppAvailable,
is(false));
}
// query content providers; directed package
{
final Intent queryIntent = new Intent(ACTION_QUERY);
queryIntent.setPackage("com.android.cts.ephemeralapp1");
final List<ResolveInfo> resolveInfo = InstrumentationRegistry.getContext()
.getPackageManager().queryIntentContentProviders(queryIntent, 0 /*flags*/);
assertThat(resolveInfo.size(), is(0));
}
// query content providers; directed component
{
final Intent queryIntent = new Intent(ACTION_QUERY);
queryIntent.setComponent(
new ComponentName("com.android.cts.ephemeralapp1",
"com.android.cts.ephemeralapp1.EphemeralProvider"));
final List<ResolveInfo> resolveInfo = InstrumentationRegistry.getContext()
.getPackageManager().queryIntentContentProviders(queryIntent, 0 /*flags*/);
assertThat(resolveInfo.size(), is(0));
}
}
@Test
public void testStartNormal() throws Exception {
// start the normal activity
{
final Intent startNormalIntent = new Intent(ACTION_START_NORMAL_ACTIVITY)
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
InstrumentationRegistry.getContext().startActivity(startNormalIntent, null /*options*/);
final TestResult testResult = getResult();
assertThat(testResult.getPackageName(),
is("com.android.cts.normalapp"));
assertThat(testResult.getComponentName(),
is("NormalActivity"));
assertThat(testResult.getException(),
is("android.content.pm.PackageManager$NameNotFoundException"));
}
// start the normal activity; directed package
{
final Intent startNormalIntent = new Intent(ACTION_START_NORMAL_ACTIVITY)
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startNormalIntent.setPackage("com.android.cts.normalapp");
InstrumentationRegistry.getContext().startActivity(startNormalIntent, null /*options*/);
final TestResult testResult = getResult();
assertThat(testResult.getPackageName(),
is("com.android.cts.normalapp"));
assertThat(testResult.getComponentName(),
is("NormalActivity"));
assertThat(testResult.getException(),
is("android.content.pm.PackageManager$NameNotFoundException"));
}
// start the normal activity; directed component
{
final Intent startNormalIntent = new Intent(ACTION_START_NORMAL_ACTIVITY)
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startNormalIntent.setComponent(new ComponentName(
"com.android.cts.normalapp", "com.android.cts.normalapp.NormalActivity"));
InstrumentationRegistry.getContext().startActivity(startNormalIntent, null /*options*/);
final TestResult testResult = getResult();
assertThat(testResult.getPackageName(),
is("com.android.cts.normalapp"));
assertThat(testResult.getComponentName(),
is("NormalActivity"));
assertThat(testResult.getException(),
is("android.content.pm.PackageManager$NameNotFoundException"));
}
// connect to the normal provider
{
final String provider = "content://com.android.cts.normalapp.provider/table";
final Cursor testCursor = InstrumentationRegistry
.getContext().getContentResolver().query(
Uri.parse(provider),
null /*projection*/,
null /*selection*/,
null /*selectionArgs*/,
null /*sortOrder*/);
assertThat(testCursor, is(notNullValue()));
assertThat(testCursor.getCount(), is(1));
assertThat(testCursor.getColumnCount(), is(2));
assertThat(testCursor.moveToFirst(), is(true));
assertThat(testCursor.getInt(0), is(1));
assertThat(testCursor.getString(1), is("NormalProvider"));
}
}
@Test
public void testStartEphemeral() throws Exception {
// start the ephemeral activity; no EXTERNAL flag
try {
final Intent startEphemeralIntent = new Intent(ACTION_START_EPHEMERAL_ACTIVITY)
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
InstrumentationRegistry.getContext().startActivity(
startEphemeralIntent, null /*options*/);
final TestResult testResult = getResult();
fail();
} catch (ActivityNotFoundException expected) {
}
// start the ephemeral activity; EXTERNAL flag
{
final Intent startEphemeralIntent = new Intent(ACTION_START_EPHEMERAL_ACTIVITY)
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_MATCH_EXTERNAL);
InstrumentationRegistry.getContext().startActivity(
startEphemeralIntent, null /*options*/);
final TestResult testResult = getResult();
assertThat("com.android.cts.ephemeralapp1", is(testResult.getPackageName()));
assertThat(ACTION_START_EPHEMERAL_ACTIVITY, is(testResult.getIntent().getAction()));
}
// start the ephemeral activity; directed package, no EXTERNAL flag
try {
final Intent startEphemeralIntent = new Intent(ACTION_START_EPHEMERAL_ACTIVITY)
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startEphemeralIntent.setPackage("com.android.cts.ephemeralapp1");
InstrumentationRegistry.getContext().startActivity(
startEphemeralIntent, null /*options*/);
final TestResult testResult = getResult();
fail();
} catch (ActivityNotFoundException expected) {
}
// start the ephemeral activity; directed package, includes EXTERNAL flag
{
final Intent startEphemeralIntent = new Intent(ACTION_START_EPHEMERAL_ACTIVITY)
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_MATCH_EXTERNAL);
startEphemeralIntent.setPackage("com.android.cts.ephemeralapp1");
InstrumentationRegistry.getContext().startActivity(
startEphemeralIntent, null /*options*/);
final TestResult testResult = getResult();
assertThat("com.android.cts.ephemeralapp1", is(testResult.getPackageName()));
assertThat(ACTION_START_EPHEMERAL_ACTIVITY, is(testResult.getIntent().getAction()));
}
// start the ephemeral activity; directed component
try {
final Intent startEphemeralIntent = new Intent(ACTION_START_EPHEMERAL_ACTIVITY)
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startEphemeralIntent.setComponent(
new ComponentName("com.android.cts.ephemeralapp1",
"com.android.cts.ephemeralapp1.EphemeralActivity"));
InstrumentationRegistry.getContext().startActivity(
startEphemeralIntent, null /*options*/);
final TestResult testResult = getResult();
fail();
} catch (ActivityNotFoundException expected) {
}
// start the ephemeral activity; using VIEW/BROWSABLE
{
final Intent startViewIntent = new Intent(Intent.ACTION_VIEW)
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startViewIntent.addCategory(Intent.CATEGORY_BROWSABLE);
startViewIntent.setData(Uri.parse("https://cts.google.com/ephemeral"));
InstrumentationRegistry.getContext().startActivity(
startViewIntent, null /*options*/);
final TestResult testResult = getResult();
assertThat("com.android.cts.ephemeralapp1", is(testResult.getPackageName()));
assertThat("EphemeralActivity", is(testResult.getComponentName()));
assertThat(Intent.ACTION_VIEW, is(testResult.getIntent().getAction()));
assertThat(testResult.getIntent().getCategories(), hasItems(Intent.CATEGORY_BROWSABLE));
assertThat("https://cts.google.com/ephemeral",
is(testResult.getIntent().getData().toString()));
}
final ContentResolver contentResolver =
InstrumentationRegistry.getContext().getContentResolver();
final int originalSetting = Secure.getInt(contentResolver, Secure.INSTANT_APPS_ENABLED, 1);
Secure.putInt(contentResolver, Secure.INSTANT_APPS_ENABLED, 0);
try {
Thread.sleep(1000);
} catch (Exception e) {
}
try {
// start the ephemeral activity; using VIEW/BROWSABLE with setting disabled
try {
final Intent startViewIntent = new Intent(Intent.ACTION_VIEW)
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startViewIntent.addCategory(Intent.CATEGORY_BROWSABLE);
startViewIntent.setData(Uri.parse("https://cts.google.com/ephemeral"));
InstrumentationRegistry.getContext().startActivity(
startViewIntent, null /*options*/);
final TestResult testResult = getResult();
fail();
} catch (TestResultNotFoundException expected) {
// we shouldn't resolve to our instant app
}
// start the ephemeral activity; EXTERNAL flag with setting disabled
{
final Intent startEphemeralIntent = new Intent(ACTION_START_EPHEMERAL_ACTIVITY)
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_MATCH_EXTERNAL);
InstrumentationRegistry.getContext().startActivity(
startEphemeralIntent, null /*options*/);
final TestResult testResult = getResult();
assertThat("com.android.cts.ephemeralapp1", is(testResult.getPackageName()));
assertThat(ACTION_START_EPHEMERAL_ACTIVITY, is(testResult.getIntent().getAction()));
}
} finally {
Secure.putInt(contentResolver, Secure.INSTANT_APPS_ENABLED, originalSetting);
}
// connect to the instant app provider
{
final String provider = "content://com.android.cts.ephemeralapp1.provider/table";
final Cursor testCursor = contentResolver.query(
Uri.parse(provider),
null /*projection*/,
null /*selection*/,
null /*selectionArgs*/,
null /*sortOrder*/);
assertThat(testCursor, is(nullValue()));
}
}
private TestResult getResult() {
final TestResult result;
try {
result = mResultQueue.poll(5, TimeUnit.SECONDS);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
if (result == null) {
throw new TestResultNotFoundException(
"Activity didn't receive a Result in 5 seconds");
}
return result;
}
private static class TestResultNotFoundException extends IllegalStateException {
public TestResultNotFoundException(String description) {
super(description);
}
}
private static class ActivityBroadcastReceiver extends BroadcastReceiver {
private final SynchronousQueue<TestResult> mQueue;
public ActivityBroadcastReceiver(SynchronousQueue<TestResult> queue) {
mQueue = queue;
}
@Override
public void onReceive(Context context, Intent intent) {
try {
mQueue.offer(intent.getParcelableExtra(TestResult.EXTRA_TEST_RESULT),
5, TimeUnit.SECONDS);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}