1 /* 2 * Copyright (C) 2021 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.bedstead.nene.packages; 18 19 import android.content.ComponentName; 20 import android.text.TextUtils; 21 22 import com.android.bedstead.nene.TestApis; 23 import com.android.bedstead.nene.annotations.Experimental; 24 import com.android.bedstead.nene.exceptions.AdbException; 25 import com.android.bedstead.nene.exceptions.NeneException; 26 import com.android.bedstead.nene.users.UserReference; 27 import com.android.bedstead.nene.utils.ShellCommand; 28 29 import java.util.Objects; 30 31 /** 32 * A representation of a component on device which may or may not exist. 33 */ 34 @Experimental 35 public class ComponentReference { 36 37 final Package mPackage; 38 final String mClassName; 39 40 private static final String CONFIG_KEY_RESOLVER_ACTIVITY = "config_customResolverActivity"; 41 private static final String DEFAULT_STRING_TYPE = "string"; 42 private static final String DEFAULT_PACKAGE_ANDROID = "android"; 43 private static final ComponentReference DEFAULT_RESOLVER_ACTIVITY = 44 new ComponentReference(TestApis.packages().find(DEFAULT_PACKAGE_ANDROID), 45 "com.android.internal.app.ResolverActivity"); 46 47 /** See {@link ComponentName#unflattenFromString(String)}. */ unflattenFromString(String string)48 public static ComponentReference unflattenFromString(String string) { 49 return new ComponentReference( 50 Objects.requireNonNull(ComponentName.unflattenFromString(string))); 51 } 52 ComponentReference(Package packageName, String className)53 public ComponentReference(Package packageName, String className) { 54 mPackage = packageName; 55 mClassName = className; 56 } 57 ComponentReference(ComponentName component)58 public ComponentReference(ComponentName component) { 59 this(new Package(component.getPackageName()), component.getClassName()); 60 } 61 62 /** 63 * Get the {@link Package} for this component. 64 */ pkg()65 public Package pkg() { 66 return mPackage; 67 } 68 69 /** 70 * Get the class for this component. 71 */ className()72 public String className() { 73 return mClassName; 74 } 75 76 /** 77 * Get this component as a {@link ComponentName}. 78 */ componentName()79 public ComponentName componentName() { 80 return new ComponentName(mPackage.packageName(), mClassName); 81 } 82 83 /** 84 * Enable this component for the given {@link UserReference}. 85 */ enable(UserReference user)86 public ComponentReference enable(UserReference user) { 87 try { 88 ShellCommand.builderForUser(user, "pm enable") 89 .addOperand(mPackage.packageName() + "/" + mClassName) 90 .validate(o -> o.contains("new state")) 91 .execute(); 92 } catch (AdbException e) { 93 throw new NeneException("Error enabling component " + this + " for user " + user, e); 94 } 95 return this; 96 } 97 98 /** 99 * See {@link ComponentName#flattenToString()}. 100 */ flattenToString()101 public String flattenToString() { 102 return componentName().flattenToString(); 103 } 104 105 /** 106 * Enable this component for the instrumented user. 107 */ enable()108 public ComponentReference enable() { 109 return enable(TestApis.users().instrumented()); 110 } 111 112 /** 113 * Disable this component for the given {@link UserReference}. 114 */ disable(UserReference user)115 public ComponentReference disable(UserReference user) { 116 try { 117 ShellCommand.builderForUser(user, "pm disable") 118 .addOperand(mPackage.packageName() + "/" + mClassName) 119 .validate(o -> o.contains("new state")) 120 .execute(); 121 } catch (AdbException e) { 122 throw new NeneException("Error disabling component " + this + " for user " + user, e); 123 } 124 return this; 125 } 126 127 /** 128 * Disable this component for the instrumented user. 129 */ disable()130 public ComponentReference disable() { 131 return disable(TestApis.users().instrumented()); 132 } 133 134 /** 135 * Checks if the activity is a {@link com.android.internal.app.ResolverActivity} 136 */ isResolver()137 public boolean isResolver() { 138 return equals(getResolverActivity()); 139 } 140 getResolverActivity()141 private ComponentReference getResolverActivity() { 142 String resolverActivity = TestApis.resources().system().getString( 143 /* name= */ CONFIG_KEY_RESOLVER_ACTIVITY, 144 /* defType= */ DEFAULT_STRING_TYPE, 145 /* defPackage= */ DEFAULT_PACKAGE_ANDROID); 146 if (TextUtils.isEmpty(resolverActivity)) { 147 return DEFAULT_RESOLVER_ACTIVITY; 148 } 149 150 return ComponentReference.unflattenFromString(resolverActivity); 151 } 152 153 @Override hashCode()154 public int hashCode() { 155 return componentName().hashCode(); 156 } 157 158 @Override equals(Object obj)159 public boolean equals(Object obj) { 160 if (!(obj instanceof ComponentReference)) { 161 return false; 162 } 163 164 ComponentReference other = (ComponentReference) obj; 165 return other.componentName().equals(componentName()); 166 } 167 168 @Override toString()169 public String toString() { 170 StringBuilder stringBuilder = new StringBuilder("ComponentReference{"); 171 stringBuilder.append("package=" + mPackage); 172 stringBuilder.append(", component=" + mClassName); 173 stringBuilder.append("}"); 174 return stringBuilder.toString(); 175 } 176 } 177