1 /* 2 * Copyright (C) 2023 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.launcher3.provider; 18 19 import static android.content.pm.LauncherApps.EXTRA_PIN_ITEM_REQUEST; 20 21 import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; 22 23 import static com.android.launcher3.LauncherSettings.Favorites.INTENT; 24 import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE; 25 26 import static org.junit.Assert.assertEquals; 27 import static org.junit.Assert.assertNotNull; 28 import static org.mockito.Mockito.doAnswer; 29 import static org.mockito.Mockito.mock; 30 import static org.mockito.Mockito.when; 31 32 import android.content.ContentValues; 33 import android.content.Context; 34 import android.content.ContextWrapper; 35 import android.content.Intent; 36 import android.content.pm.LauncherApps.PinItemRequest; 37 import android.content.pm.ShortcutInfo; 38 import android.content.pm.ShortcutManager; 39 import android.database.Cursor; 40 import android.database.sqlite.SQLiteDatabase; 41 import android.net.Uri; 42 import android.os.Process; 43 44 import com.android.launcher3.LauncherSettings.Favorites; 45 import com.android.launcher3.R; 46 import com.android.launcher3.model.DatabaseHelper; 47 import com.android.launcher3.model.DbDowngradeHelper; 48 import com.android.launcher3.pm.UserCache; 49 import com.android.launcher3.settings.SettingsActivity; 50 import com.android.launcher3.shortcuts.ShortcutKey; 51 import com.android.launcher3.util.IOUtils; 52 53 import org.junit.Before; 54 import org.junit.Test; 55 import org.mockito.ArgumentCaptor; 56 57 import java.io.InputStream; 58 59 /** 60 * Test for {@link LauncherDbUtils}. 61 */ 62 public class LauncherDbUtilsTest { 63 64 private Context mContext; 65 private ArgumentCaptor<ShortcutInfo> mInfoArgumentCaptor; 66 private boolean mPinningAllowed = true; 67 68 @Before setup()69 public void setup() { 70 PinItemRequest req = mock(PinItemRequest.class); 71 doAnswer(i -> mPinningAllowed).when(req).accept(); 72 73 mInfoArgumentCaptor = ArgumentCaptor.forClass(ShortcutInfo.class); 74 ShortcutManager sm = mock(ShortcutManager.class); 75 when(sm.createShortcutResultIntent(mInfoArgumentCaptor.capture())) 76 .thenReturn(new Intent().putExtra(EXTRA_PIN_ITEM_REQUEST, req)); 77 78 mContext = new ContextWrapper(getInstrumentation().getTargetContext()) { 79 80 @Override 81 public Object getSystemService(String name) { 82 return SHORTCUT_SERVICE.equals(name) ? sm : super.getSystemService(name); 83 } 84 }; 85 } 86 87 @Test migrateLegacyShortcuts_invalidIntent()88 public void migrateLegacyShortcuts_invalidIntent() throws Exception { 89 SQLiteDatabase db = setupLegacyShortcut(null); 90 assertEquals(1, getFavoriteDataCount(db)); 91 92 LauncherDbUtils.migrateLegacyShortcuts(mContext, db); 93 94 assertEquals(0, getFavoriteDataCount(db)); 95 } 96 97 @Test migrateLegacyShortcuts_protectedIntent()98 public void migrateLegacyShortcuts_protectedIntent() throws Exception { 99 Intent intent = new Intent(Intent.ACTION_CALL) 100 .setData(Uri.parse("tel:0000000000")); 101 SQLiteDatabase db = setupLegacyShortcut(intent); 102 assertEquals(1, getFavoriteDataCount(db)); 103 104 LauncherDbUtils.migrateLegacyShortcuts(mContext, db); 105 106 assertEquals(0, getFavoriteDataCount(db)); 107 } 108 109 @Test migrateLegacyShortcuts_pinningDisabled()110 public void migrateLegacyShortcuts_pinningDisabled() throws Exception { 111 mPinningAllowed = false; 112 Intent intent = new Intent(mContext, SettingsActivity.class); 113 SQLiteDatabase db = setupLegacyShortcut(intent); 114 assertEquals(1, getFavoriteDataCount(db)); 115 116 LauncherDbUtils.migrateLegacyShortcuts(mContext, db); 117 118 assertEquals(0, getFavoriteDataCount(db)); 119 } 120 121 @Test migrateLegacyShortcuts_success()122 public void migrateLegacyShortcuts_success() throws Exception { 123 Intent intent = new Intent(mContext, SettingsActivity.class); 124 SQLiteDatabase db = setupLegacyShortcut(intent); 125 assertEquals(1, getFavoriteDataCount(db)); 126 127 LauncherDbUtils.migrateLegacyShortcuts(mContext, db); 128 129 assertEquals(1, getFavoriteDataCount(db)); 130 ShortcutInfo info = mInfoArgumentCaptor.getValue(); 131 assertNotNull(info); 132 try (Cursor c = db.query(Favorites.TABLE_NAME, null, null, null, null, null, null)) { 133 c.moveToNext(); 134 assertEquals(Favorites.ITEM_TYPE_DEEP_SHORTCUT, c.getInt(c.getColumnIndex(ITEM_TYPE))); 135 136 ShortcutKey key = ShortcutKey.fromIntent( 137 Intent.parseUri(c.getString(c.getColumnIndex(INTENT)), 0), 138 Process.myUserHandle()); 139 140 assertEquals(info.getId(), key.getId()); 141 assertEquals(info.getPackage(), key.getPackageName()); 142 } 143 } 144 setupLegacyShortcut(Intent intent)145 private SQLiteDatabase setupLegacyShortcut(Intent intent) throws Exception { 146 SQLiteDatabase db = new MyDatabaseHelper().getWritableDatabase(); 147 try (InputStream in = mContext.getResources().openRawResource(R.raw.downgrade_schema)) { 148 DbDowngradeHelper.parse(IOUtils.toByteArray(in)).onDowngrade(db, db.getVersion(), 31); 149 } 150 151 ContentValues cv = new ContentValues(); 152 cv.put("itemType", 1); 153 cv.put("title", "Hello"); 154 cv.put("intent", intent == null ? null : intent.toUri(0)); 155 db.insert(Favorites.TABLE_NAME, null, cv); 156 return db; 157 } 158 getFavoriteDataCount(SQLiteDatabase db)159 public static int getFavoriteDataCount(SQLiteDatabase db) { 160 try (Cursor c = db.query(Favorites.TABLE_NAME, null, null, null, null, null, null)) { 161 return c.getCount(); 162 } 163 } 164 165 private class MyDatabaseHelper extends DatabaseHelper { 166 MyDatabaseHelper()167 MyDatabaseHelper() { 168 super(mContext, null, UserCache.INSTANCE.get(mContext)::getSerialNumberForUser, 169 () -> { }); 170 } 171 172 @Override handleOneTimeDataUpgrade(SQLiteDatabase db)173 protected void handleOneTimeDataUpgrade(SQLiteDatabase db) { } 174 } 175 } 176