/* * 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 com.android.textclassifier.testing; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import android.content.ComponentName; import android.content.Context; import android.content.ContextWrapper; import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import androidx.test.core.app.ApplicationProvider; import com.google.common.base.Preconditions; import java.util.HashMap; import java.util.Map; import java.util.UUID; import javax.annotation.Nullable; import org.mockito.stubbing.Answer; /** A builder used to build a fake context for testing. */ public final class FakeContextBuilder { /** A component name that can be used for tests. */ public static final ComponentName DEFAULT_COMPONENT = new ComponentName("pkg", "cls"); private final PackageManager packageManager; private final ContextWrapper context; private final Map components = new HashMap<>(); private final Map appLabels = new HashMap<>(); @Nullable private ComponentName allIntentComponent; public FakeContextBuilder() { packageManager = mock(PackageManager.class); when(packageManager.resolveActivity(any(Intent.class), anyInt())).thenReturn(null); context = new ContextWrapper(ApplicationProvider.getApplicationContext()) { @Override public PackageManager getPackageManager() { return packageManager; } }; } /** * Sets the component name of an activity to handle the specified intent action. * *

NOTE: By default, no component is set to handle any intent. */ public FakeContextBuilder setIntentComponent( String intentAction, @Nullable ComponentName component) { Preconditions.checkNotNull(intentAction); components.put(intentAction, component); return this; } /** Sets the app label res for a specified package. */ public FakeContextBuilder setAppLabel(String packageName, @Nullable CharSequence appLabel) { Preconditions.checkNotNull(packageName); appLabels.put(packageName, appLabel); return this; } /** * Sets the component name of an activity to handle all intents. * *

NOTE: By default, no component is set to handle any intent. */ public FakeContextBuilder setAllIntentComponent(@Nullable ComponentName component) { allIntentComponent = component; return this; } /** Builds and returns a fake context. */ public Context build() { when(packageManager.resolveActivity(any(Intent.class), anyInt())) .thenAnswer( (Answer) invocation -> { final String action = ((Intent) invocation.getArgument(0)).getAction(); final ComponentName component = components.containsKey(action) ? components.get(action) : allIntentComponent; return getResolveInfo(component); }); when(packageManager.getApplicationLabel(any(ApplicationInfo.class))) .thenAnswer( (Answer) invocation -> { ApplicationInfo applicationInfo = invocation.getArgument(0); return appLabels.get(applicationInfo.packageName); }); return context; } /** Returns a component name with random package and class names. */ public static ComponentName newComponent() { return new ComponentName(UUID.randomUUID().toString(), UUID.randomUUID().toString()); } private static ResolveInfo getResolveInfo(ComponentName component) { final ResolveInfo info; if (component == null) { info = null; } else { // NOTE: If something breaks in TextClassifier because we expect more fields to be set // in here, just add them. info = new ResolveInfo(); info.activityInfo = new ActivityInfo(); info.activityInfo.packageName = component.getPackageName(); info.activityInfo.name = component.getClassName(); info.activityInfo.exported = true; info.activityInfo.applicationInfo = new ApplicationInfo(); info.activityInfo.applicationInfo.packageName = component.getPackageName(); info.activityInfo.applicationInfo.icon = 0; } return info; } }