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 android.security.cts.CVE_2021_0481; 18 19 import org.junit.Before; 20 import org.junit.Test; 21 import org.junit.runner.RunWith; 22 23 import android.content.Context; 24 import android.content.Intent; 25 import android.content.pm.PackageManager; 26 import android.content.pm.ResolveInfo; 27 import android.os.SystemClock; 28 import android.util.Log; 29 30 import static androidx.test.core.app.ApplicationProvider.getApplicationContext; 31 import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; 32 import androidx.test.filters.SdkSuppress; 33 import androidx.test.runner.AndroidJUnit4; 34 import androidx.test.uiautomator.By; 35 import androidx.test.uiautomator.UiDevice; 36 import androidx.test.uiautomator.UiObject2; 37 import androidx.test.uiautomator.Until; 38 import androidx.test.uiautomator.BySelector; 39 40 import java.util.List; 41 42 import static org.hamcrest.CoreMatchers.equalTo; 43 import static org.hamcrest.CoreMatchers.is; 44 import static org.hamcrest.CoreMatchers.notNullValue; 45 import static org.junit.Assert.assertThat; 46 import static org.junit.Assert.assertFalse; 47 import static org.junit.Assume.assumeNoException; 48 49 /** 50 * launch "Settings" app 51 * set up user photo 52 */ 53 @RunWith(AndroidJUnit4.class) 54 public class DeviceTest { 55 56 class ClickableNotFound extends Exception{ ClickableNotFound(String s)57 public ClickableNotFound(String s){ 58 super(s); 59 } 60 } 61 62 private static final String BASIC_SAMPLE_PACKAGE 63 = "android.security.cts.CVE_2021_0481"; 64 private static final int LAUNCH_TIMEOUT_MS = 20000; 65 private static final String TAG = "TAG_2021_0481"; 66 private static final int IS_FOUND_FLAG = 1; // 0001 67 private static final int IS_CHECKED_FLAG = 2; // 0010 68 private UiDevice mDevice; 69 70 @Test testUserPhotoSetUp()71 public void testUserPhotoSetUp() { 72 73 //set mDevice and go to homescreen 74 mDevice = UiDevice.getInstance(getInstrumentation()); 75 mDevice.pressHome(); 76 77 //start "Settings" app 78 Intent myIntent = new Intent("android.settings.USER_SETTINGS"); 79 //android.provider.Settings.ACTION_USER_SETTINGS 80 myIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 81 try{ 82 getApplicationContext().startActivity(myIntent); 83 } catch(android.content.ActivityNotFoundException e){ 84 Log.d(TAG, "Activity to be tested doesn't exist. Test will pass."); 85 return; 86 } 87 88 //wait for "User Settings" activity to appear. 89 SystemClock.sleep(6000); 90 91 //perform UI test steps 92 try { 93 94 //in "Multiple users" activity showing "Use multiple users" switch 95 searchAndClick(mDevice, "android:id/switch_widget", 2000); 96 97 //in "Multiple users" activity showing a list of current users, 98 //look for the first item "android:id/title" on the list showing "You(Owner)" 99 searchAndClick(mDevice, "android:id/title", 2000); 100 101 //in "Profile Info" dialog window showing clickable user silhouette 102 //look for clickable android.widget.ImageView object with attributes: 103 // getContentDescription()=Select photo 104 // getResourceName()=com.android.settings:id/user_photo 105 searchAndClick(mDevice, "com.android.settings:id/user_photo", 2000); 106 107 //in unnamed subdialog showing two options: "Take a photo" "Choose an image" 108 searchAndClick(mDevice, "Choose an image", 6000); 109 110 //in "Browse Files in Other Apps" activity 111 searchAndClick(mDevice, "android.security.cts.CVE_2021_0481.EvilActivity", 5000); 112 113 //Image is chosen as (evilActivity) so we are getting back to 114 //"Profile Info" dialog window showing clickable user silhouette 115 //end "Cancel" and "OK" buttons. 116 //look for "Cancel button and click it" 117 searchAndClick(mDevice, "Cancel", 2000); 118 119 } catch (ClickableNotFound e){ 120 Log.d(TAG, e.toString()); 121 assumeNoException(e); 122 } 123 Log.d(TAG, "end of testUserPhotoSetUp()"); 124 } 125 126 //see what is on screen and click on object containing name 127 //throw exception if object not found searchAndClick(UiDevice mDevice, String name, int timeOut)128 private void searchAndClick(UiDevice mDevice, String name, int timeOut) throws ClickableNotFound { 129 130 int ret; 131 List<UiObject2> objects = mDevice.findObjects(By.clickable(true)); 132 boolean found = false; 133 Log.d(TAG, "looking for " + name); 134 Log.d(TAG, "found " + String.valueOf(objects!=null ? objects.size() : 0) + " clickables"); 135 136 if(objects != null){ 137 for (UiObject2 o : objects) { 138 if((ret=searchAndLog(o, name, "")) !=0 ) 139 { 140 found=true; 141 Log.d(TAG, name + " found"); 142 if((ret & IS_CHECKED_FLAG) == 0) { 143 o.click(); 144 Log.d(TAG, name + " clicked"); 145 SystemClock.sleep(timeOut); //wait for click result to appear onscreen 146 } 147 break; //to avoid androidx.test.uiautomator.StaleObjectException 148 } 149 } 150 } 151 if(!found) { 152 throw new ClickableNotFound("\"" + name + "\" not found to click on"); 153 } 154 } 155 156 //Search for 'name' in UiObject2 157 //returns int flags showing search result: 158 // IS_CHECKED_FLAG - 'name' matches o.getResourceName() and o.isSelected()==true 159 // IS_FOUND_FLAG - 'name' matches anything else searchAndLog(UiObject2 o, String name, String prefix)160 private int searchAndLog(UiObject2 o, String name, String prefix){ 161 162 int ret = 0; 163 String lname = o.getText(); 164 String cname = o.getClassName(); 165 String cdesc = o.getContentDescription(); 166 String rname = o.getResourceName(); 167 boolean checked = o.isChecked(); 168 169 Log.d(TAG, prefix + "class=" + cname); 170 Log.d(TAG, prefix + "o.getText()=" + lname); 171 Log.d(TAG, prefix + "o.getContentDescription()=" + cdesc); 172 Log.d(TAG, prefix + "o.getResourceName()=" + rname); 173 Log.d(TAG, prefix + "o.getChildCount()=" + o.getChildCount()); 174 175 if( rname != null && rname.equals(name) && checked) { 176 ret |= IS_CHECKED_FLAG; 177 } 178 else if(lname != null && lname.equals(name) || cdesc != null && cdesc.equals(name) || rname != null && rname.equals(name) ) { 179 ret |= IS_FOUND_FLAG; 180 } 181 182 if(ret != 0) { 183 Log.d(TAG, prefix + "found-->" + name); 184 return ret; 185 } else { 186 java.util.List<UiObject2> objects2 = o.getChildren(); 187 if(objects2 != null && objects2.size() > 0 && prefix.length() < 50) { 188 for (UiObject2 o2 : objects2) { 189 if((ret=searchAndLog(o2, name, prefix + "__")) != 0){ 190 return ret; 191 } 192 } 193 } 194 } 195 return ret; 196 } 197 198 } 199 200