1fefcd700d6b4cf1c4402af74c50fb0e762472901Steve McKay/* 2fefcd700d6b4cf1c4402af74c50fb0e762472901Steve McKay * Copyright (C) 2015 The Android Open Source Project 3fefcd700d6b4cf1c4402af74c50fb0e762472901Steve McKay * 4fefcd700d6b4cf1c4402af74c50fb0e762472901Steve McKay * Licensed under the Apache License, Version 2.0 (the "License"); 5fefcd700d6b4cf1c4402af74c50fb0e762472901Steve McKay * you may not use this file except in compliance with the License. 6fefcd700d6b4cf1c4402af74c50fb0e762472901Steve McKay * You may obtain a copy of the License at 7fefcd700d6b4cf1c4402af74c50fb0e762472901Steve McKay * 8fefcd700d6b4cf1c4402af74c50fb0e762472901Steve McKay * http://www.apache.org/licenses/LICENSE-2.0 9fefcd700d6b4cf1c4402af74c50fb0e762472901Steve McKay * 10fefcd700d6b4cf1c4402af74c50fb0e762472901Steve McKay * Unless required by applicable law or agreed to in writing, software 11fefcd700d6b4cf1c4402af74c50fb0e762472901Steve McKay * distributed under the License is distributed on an "AS IS" BASIS, 12fefcd700d6b4cf1c4402af74c50fb0e762472901Steve McKay * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13fefcd700d6b4cf1c4402af74c50fb0e762472901Steve McKay * See the License for the specific language governing permissions and 14fefcd700d6b4cf1c4402af74c50fb0e762472901Steve McKay * limitations under the License. 15fefcd700d6b4cf1c4402af74c50fb0e762472901Steve McKay */ 16fefcd700d6b4cf1c4402af74c50fb0e762472901Steve McKay 17d9caa6ab53aa784acaf241c0ded3c4ae2d342bf8Steve McKaypackage com.android.documentsui.base; 18fefcd700d6b4cf1c4402af74c50fb0e762472901Steve McKay 195b0a2c187a9e446b683687817d22cbe443585223Steve McKayimport android.annotation.PluralsRes; 2024917427f41f9e41925c4a56d0c71d85e30643dfSteve McKayimport android.app.Activity; 2117f7e5891cbe86fc6cacae045a4edd3e41f8d5eeSteve McKayimport android.app.AlertDialog; 220ce04b7a3f2c76452f855d082cd57d5e4cab9d69Steve McKayimport android.content.ContentResolver; 23919231857d2add3afe51f06aaf41663a252c3e0eBen Kwaimport android.content.Context; 2417f7e5891cbe86fc6cacae045a4edd3e41f8d5eeSteve McKayimport android.content.Intent; 25988d8a354b00dce7e24deee187c08a4591956ac9Steve McKayimport android.content.pm.ApplicationInfo; 2600ee050745f8c3558e7ee93d56abeb0a4ad82472Steve McKayimport android.content.pm.PackageManager.NameNotFoundException; 27741ac6fffb3ee2441569412a28a1c4f3c2160d87Aga Wronskaimport android.content.res.Configuration; 28988d8a354b00dce7e24deee187c08a4591956ac9Steve McKayimport android.net.Uri; 29531d402b29ba4894ccef7e302f6902c07619966fGarfield Tanimport android.os.Build; 302056205cb85d529d732638c45fe459168168e1eeGarfield, Tanimport android.os.Looper; 3117f7e5891cbe86fc6cacae045a4edd3e41f8d5eeSteve McKayimport android.provider.DocumentsContract; 320ce04b7a3f2c76452f855d082cd57d5e4cab9d69Steve McKayimport android.provider.Settings; 3355c00e7356d9f76e7378cf7c701b9a41cb7be6daSteve McKayimport android.text.TextUtils; 348e3fd7676023738c04d099f2940a635ff0699717Ben Kwaimport android.text.format.DateUtils; 358e3fd7676023738c04d099f2940a635ff0699717Ben Kwaimport android.text.format.Time; 362056205cb85d529d732638c45fe459168168e1eeGarfield, Tanimport android.util.Log; 37741ac6fffb3ee2441569412a28a1c4f3c2160d87Aga Wronskaimport android.view.WindowManager; 386d50bcc90e6f8b3c16e23b3fc2d63f57804dd805Aga Wronska 39d9caa6ab53aa784acaf241c0ded3c4ae2d342bf8Steve McKayimport com.android.documentsui.R; 40da2c0f0b075ad9f770182e706c2ec158989568a7Garfield Tanimport com.android.documentsui.ui.MessageBuilder; 41d9caa6ab53aa784acaf241c0ded3c4ae2d342bf8Steve McKay 42e77419c6b4aecf4eb71b49898d6b63034a0771e4Ben Linimport java.io.PrintWriter; 43e77419c6b4aecf4eb71b49898d6b63034a0771e4Ben Linimport java.io.StringWriter; 4455c00e7356d9f76e7378cf7c701b9a41cb7be6daSteve McKayimport java.text.Collator; 45c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKayimport java.util.ArrayList; 46c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKayimport java.util.List; 47c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay 4885ec0d676297724f211213c7cb188839f1d3601bSteve McKayimport javax.annotation.Nullable; 4985ec0d676297724f211213c7cb188839f1d3601bSteve McKay 504d0255f79cc92a5675d14b20f9cdf06ecb8d7109Steve McKay/** @hide */ 51fefcd700d6b4cf1c4402af74c50fb0e762472901Steve McKaypublic final class Shared { 5255c00e7356d9f76e7378cf7c701b9a41cb7be6daSteve McKay 530af8afd3309538dec784ed0c9c35b252a8213123Steve McKay public static final String TAG = "Documents"; 540af8afd3309538dec784ed0c9c35b252a8213123Steve McKay 55531d402b29ba4894ccef7e302f6902c07619966fGarfield Tan public static final boolean DEBUG = Build.IS_DEBUGGABLE; 5630535bce902104c97bbf70783d684ee673cb7637Steve McKay public static final boolean VERBOSE = DEBUG && Log.isLoggable(TAG, Log.VERBOSE); 570af8afd3309538dec784ed0c9c35b252a8213123Steve McKay 58ae96780a8909476dca709b88dbae5ec9a2f0632cBen Kwa /** Intent action name to pick a copy destination. */ 59ae96780a8909476dca709b88dbae5ec9a2f0632cBen Kwa public static final String ACTION_PICK_COPY_DESTINATION = 60ae96780a8909476dca709b88dbae5ec9a2f0632cBen Kwa "com.android.documentsui.PICK_COPY_DESTINATION"; 61ae96780a8909476dca709b88dbae5ec9a2f0632cBen Kwa 62ae96780a8909476dca709b88dbae5ec9a2f0632cBen Kwa /** 631686883a8d049b399e34954a4feaa98490277ae8Garfield Tan * Extra boolean flag for {@link #ACTION_PICK_COPY_DESTINATION}, which 64ae96780a8909476dca709b88dbae5ec9a2f0632cBen Kwa * specifies if the destination directory needs to create new directory or not. 65ae96780a8909476dca709b88dbae5ec9a2f0632cBen Kwa */ 66ae96780a8909476dca709b88dbae5ec9a2f0632cBen Kwa public static final String EXTRA_DIRECTORY_COPY = "com.android.documentsui.DIRECTORY_COPY"; 6717f7e5891cbe86fc6cacae045a4edd3e41f8d5eeSteve McKay 6817f7e5891cbe86fc6cacae045a4edd3e41f8d5eeSteve McKay /** 6917f7e5891cbe86fc6cacae045a4edd3e41f8d5eeSteve McKay * Extra flag used to store the current stack so user opens in right spot. 7017f7e5891cbe86fc6cacae045a4edd3e41f8d5eeSteve McKay */ 71af5ace5d5e3a273b151e012206efd029c2872b59Aga Wronska public static final String EXTRA_STACK = "com.android.documentsui.STACK"; 72af5ace5d5e3a273b151e012206efd029c2872b59Aga Wronska 73af5ace5d5e3a273b151e012206efd029c2872b59Aga Wronska /** 74af5ace5d5e3a273b151e012206efd029c2872b59Aga Wronska * Extra flag used to store query of type String in the bundle. 75af5ace5d5e3a273b151e012206efd029c2872b59Aga Wronska */ 76af5ace5d5e3a273b151e012206efd029c2872b59Aga Wronska public static final String EXTRA_QUERY = "query"; 77af5ace5d5e3a273b151e012206efd029c2872b59Aga Wronska 78af5ace5d5e3a273b151e012206efd029c2872b59Aga Wronska /** 79af5ace5d5e3a273b151e012206efd029c2872b59Aga Wronska * Extra flag used to store state of type State in the bundle. 80af5ace5d5e3a273b151e012206efd029c2872b59Aga Wronska */ 81af5ace5d5e3a273b151e012206efd029c2872b59Aga Wronska public static final String EXTRA_STATE = "state"; 82af5ace5d5e3a273b151e012206efd029c2872b59Aga Wronska 83af5ace5d5e3a273b151e012206efd029c2872b59Aga Wronska /** 84af5ace5d5e3a273b151e012206efd029c2872b59Aga Wronska * Extra flag used to store root of type RootInfo in the bundle. 85af5ace5d5e3a273b151e012206efd029c2872b59Aga Wronska */ 86af5ace5d5e3a273b151e012206efd029c2872b59Aga Wronska public static final String EXTRA_ROOT = "root"; 87af5ace5d5e3a273b151e012206efd029c2872b59Aga Wronska 88af5ace5d5e3a273b151e012206efd029c2872b59Aga Wronska /** 89af5ace5d5e3a273b151e012206efd029c2872b59Aga Wronska * Extra flag used to store document of DocumentInfo type in the bundle. 90af5ace5d5e3a273b151e012206efd029c2872b59Aga Wronska */ 91af5ace5d5e3a273b151e012206efd029c2872b59Aga Wronska public static final String EXTRA_DOC = "document"; 92af5ace5d5e3a273b151e012206efd029c2872b59Aga Wronska 93af5ace5d5e3a273b151e012206efd029c2872b59Aga Wronska /** 94af5ace5d5e3a273b151e012206efd029c2872b59Aga Wronska * Extra flag used to store DirectoryFragment's selection of Selection type in the bundle. 95af5ace5d5e3a273b151e012206efd029c2872b59Aga Wronska */ 96af5ace5d5e3a273b151e012206efd029c2872b59Aga Wronska public static final String EXTRA_SELECTION = "selection"; 97af5ace5d5e3a273b151e012206efd029c2872b59Aga Wronska 98af5ace5d5e3a273b151e012206efd029c2872b59Aga Wronska /** 99af5ace5d5e3a273b151e012206efd029c2872b59Aga Wronska * Extra flag used to store DirectoryFragment's ignore state of boolean type in the bundle. 100af5ace5d5e3a273b151e012206efd029c2872b59Aga Wronska */ 101af5ace5d5e3a273b151e012206efd029c2872b59Aga Wronska public static final String EXTRA_IGNORE_STATE = "ignoreState"; 102ae96780a8909476dca709b88dbae5ec9a2f0632cBen Kwa 103b8373c22f1bacf194c35a45dde337cad2e904587Tomasz Mikolajewski /** 104b8373c22f1bacf194c35a45dde337cad2e904587Tomasz Mikolajewski * Extra for an Intent for enabling performance benchmark. Used only by tests. 105b8373c22f1bacf194c35a45dde337cad2e904587Tomasz Mikolajewski */ 106b8373c22f1bacf194c35a45dde337cad2e904587Tomasz Mikolajewski public static final String EXTRA_BENCHMARK = "com.android.documentsui.benchmark"; 107b8373c22f1bacf194c35a45dde337cad2e904587Tomasz Mikolajewski 1082ccad1e19bb5e9308ff06c90327de99cc509f613Tomasz Mikolajewski /** 10984440eb493a8fe63c0b7f74d75f24409a32c05beSteve McKay * Extra flag used to signify to inspector that debug section can be shown. 11084440eb493a8fe63c0b7f74d75f24409a32c05beSteve McKay */ 11184440eb493a8fe63c0b7f74d75f24409a32c05beSteve McKay public static final String EXTRA_SHOW_DEBUG = "com.android.documentsui.SHOW_DEBUG"; 11284440eb493a8fe63c0b7f74d75f24409a32c05beSteve McKay 11384440eb493a8fe63c0b7f74d75f24409a32c05beSteve McKay /** 1142ccad1e19bb5e9308ff06c90327de99cc509f613Tomasz Mikolajewski * Maximum number of items in a Binder transaction packet. 1152ccad1e19bb5e9308ff06c90327de99cc509f613Tomasz Mikolajewski */ 11684769b8205cf4a100c9d4f65c41cf72ba7a3b40fSteve McKay public static final int MAX_DOCS_IN_INTENT = 500; 1172ccad1e19bb5e9308ff06c90327de99cc509f613Tomasz Mikolajewski 11883ac678e3ee261f3413486b4a2f9bd6337a820a8Steve McKay /** 11983ac678e3ee261f3413486b4a2f9bd6337a820a8Steve McKay * Animation duration of checkbox in directory list/grid in millis. 12083ac678e3ee261f3413486b4a2f9bd6337a820a8Steve McKay */ 12183ac678e3ee261f3413486b4a2f9bd6337a820a8Steve McKay public static final int CHECK_ANIMATION_DURATION = 100; 12283ac678e3ee261f3413486b4a2f9bd6337a820a8Steve McKay 12355c00e7356d9f76e7378cf7c701b9a41cb7be6daSteve McKay private static final Collator sCollator; 12455c00e7356d9f76e7378cf7c701b9a41cb7be6daSteve McKay 12555c00e7356d9f76e7378cf7c701b9a41cb7be6daSteve McKay static { 12655c00e7356d9f76e7378cf7c701b9a41cb7be6daSteve McKay sCollator = Collator.getInstance(); 12755c00e7356d9f76e7378cf7c701b9a41cb7be6daSteve McKay sCollator.setStrength(Collator.SECONDARY); 12855c00e7356d9f76e7378cf7c701b9a41cb7be6daSteve McKay } 12955c00e7356d9f76e7378cf7c701b9a41cb7be6daSteve McKay 130919231857d2add3afe51f06aaf41663a252c3e0eBen Kwa /** 131da2c0f0b075ad9f770182e706c2ec158989568a7Garfield Tan * @deprecated use {@link MessageBuilder#getQuantityString} 132919231857d2add3afe51f06aaf41663a252c3e0eBen Kwa */ 1335b0a2c187a9e446b683687817d22cbe443585223Steve McKay @Deprecated 1345b0a2c187a9e446b683687817d22cbe443585223Steve McKay public static final String getQuantityString(Context context, @PluralsRes int resourceId, int quantity) { 135919231857d2add3afe51f06aaf41663a252c3e0eBen Kwa return context.getResources().getQuantityString(resourceId, quantity, quantity); 136919231857d2add3afe51f06aaf41663a252c3e0eBen Kwa } 1378e3fd7676023738c04d099f2940a635ff0699717Ben Kwa 1388e3fd7676023738c04d099f2940a635ff0699717Ben Kwa public static String formatTime(Context context, long when) { 1398e3fd7676023738c04d099f2940a635ff0699717Ben Kwa // TODO: DateUtils should make this easier 1408e3fd7676023738c04d099f2940a635ff0699717Ben Kwa Time then = new Time(); 1418e3fd7676023738c04d099f2940a635ff0699717Ben Kwa then.set(when); 1428e3fd7676023738c04d099f2940a635ff0699717Ben Kwa Time now = new Time(); 1438e3fd7676023738c04d099f2940a635ff0699717Ben Kwa now.setToNow(); 1448e3fd7676023738c04d099f2940a635ff0699717Ben Kwa 1458e3fd7676023738c04d099f2940a635ff0699717Ben Kwa int flags = DateUtils.FORMAT_NO_NOON | DateUtils.FORMAT_NO_MIDNIGHT 1468e3fd7676023738c04d099f2940a635ff0699717Ben Kwa | DateUtils.FORMAT_ABBREV_ALL; 1478e3fd7676023738c04d099f2940a635ff0699717Ben Kwa 1488e3fd7676023738c04d099f2940a635ff0699717Ben Kwa if (then.year != now.year) { 1498e3fd7676023738c04d099f2940a635ff0699717Ben Kwa flags |= DateUtils.FORMAT_SHOW_YEAR | DateUtils.FORMAT_SHOW_DATE; 1508e3fd7676023738c04d099f2940a635ff0699717Ben Kwa } else if (then.yearDay != now.yearDay) { 1518e3fd7676023738c04d099f2940a635ff0699717Ben Kwa flags |= DateUtils.FORMAT_SHOW_DATE; 1528e3fd7676023738c04d099f2940a635ff0699717Ben Kwa } else { 1538e3fd7676023738c04d099f2940a635ff0699717Ben Kwa flags |= DateUtils.FORMAT_SHOW_TIME; 1548e3fd7676023738c04d099f2940a635ff0699717Ben Kwa } 1558e3fd7676023738c04d099f2940a635ff0699717Ben Kwa 1568e3fd7676023738c04d099f2940a635ff0699717Ben Kwa return DateUtils.formatDateTime(context, when, flags); 1578e3fd7676023738c04d099f2940a635ff0699717Ben Kwa } 1588e3fd7676023738c04d099f2940a635ff0699717Ben Kwa 159c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay /** 160c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay * A convenient way to transform any list into a (parcelable) ArrayList. 161c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay * Uses cast if possible, else creates a new list with entries from {@code list}. 162c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay */ 163c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay public static <T> ArrayList<T> asArrayList(List<T> list) { 164c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay return list instanceof ArrayList 165c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay ? (ArrayList<T>) list 166988d8a354b00dce7e24deee187c08a4591956ac9Steve McKay : new ArrayList<>(list); 167c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay } 16855c00e7356d9f76e7378cf7c701b9a41cb7be6daSteve McKay 16955c00e7356d9f76e7378cf7c701b9a41cb7be6daSteve McKay /** 17055c00e7356d9f76e7378cf7c701b9a41cb7be6daSteve McKay * Compare two strings against each other using system default collator in a 17106b036f0236149aa8f19a3ededf3d66ba2121a8dTomasz Mikolajewski * case-insensitive mode. Clusters strings prefixed with {@link DIR_PREFIX} 17206b036f0236149aa8f19a3ededf3d66ba2121a8dTomasz Mikolajewski * before other items. 17355c00e7356d9f76e7378cf7c701b9a41cb7be6daSteve McKay */ 17455c00e7356d9f76e7378cf7c701b9a41cb7be6daSteve McKay public static int compareToIgnoreCaseNullable(String lhs, String rhs) { 17555c00e7356d9f76e7378cf7c701b9a41cb7be6daSteve McKay final boolean leftEmpty = TextUtils.isEmpty(lhs); 17655c00e7356d9f76e7378cf7c701b9a41cb7be6daSteve McKay final boolean rightEmpty = TextUtils.isEmpty(rhs); 17755c00e7356d9f76e7378cf7c701b9a41cb7be6daSteve McKay 17855c00e7356d9f76e7378cf7c701b9a41cb7be6daSteve McKay if (leftEmpty && rightEmpty) return 0; 17955c00e7356d9f76e7378cf7c701b9a41cb7be6daSteve McKay if (leftEmpty) return -1; 18055c00e7356d9f76e7378cf7c701b9a41cb7be6daSteve McKay if (rightEmpty) return 1; 18155c00e7356d9f76e7378cf7c701b9a41cb7be6daSteve McKay 18255c00e7356d9f76e7378cf7c701b9a41cb7be6daSteve McKay return sCollator.compare(lhs, rhs); 18355c00e7356d9f76e7378cf7c701b9a41cb7be6daSteve McKay } 184741ac6fffb3ee2441569412a28a1c4f3c2160d87Aga Wronska 185988d8a354b00dce7e24deee187c08a4591956ac9Steve McKay /** 186988d8a354b00dce7e24deee187c08a4591956ac9Steve McKay * Returns the calling package, possibly overridden by EXTRA_PACKAGE_NAME. 187988d8a354b00dce7e24deee187c08a4591956ac9Steve McKay * @param activity 188988d8a354b00dce7e24deee187c08a4591956ac9Steve McKay * @return 189988d8a354b00dce7e24deee187c08a4591956ac9Steve McKay */ 190988d8a354b00dce7e24deee187c08a4591956ac9Steve McKay public static String getCallingPackageName(Activity activity) { 191988d8a354b00dce7e24deee187c08a4591956ac9Steve McKay String callingPackage = activity.getCallingPackage(); 192988d8a354b00dce7e24deee187c08a4591956ac9Steve McKay // System apps can set the calling package name using an extra. 193988d8a354b00dce7e24deee187c08a4591956ac9Steve McKay try { 194988d8a354b00dce7e24deee187c08a4591956ac9Steve McKay ApplicationInfo info = 195988d8a354b00dce7e24deee187c08a4591956ac9Steve McKay activity.getPackageManager().getApplicationInfo(callingPackage, 0); 196988d8a354b00dce7e24deee187c08a4591956ac9Steve McKay if (info.isSystemApp() || info.isUpdatedSystemApp()) { 197988d8a354b00dce7e24deee187c08a4591956ac9Steve McKay final String extra = activity.getIntent().getStringExtra( 198988d8a354b00dce7e24deee187c08a4591956ac9Steve McKay DocumentsContract.EXTRA_PACKAGE_NAME); 19900ee050745f8c3558e7ee93d56abeb0a4ad82472Steve McKay if (extra != null && !TextUtils.isEmpty(extra)) { 200988d8a354b00dce7e24deee187c08a4591956ac9Steve McKay callingPackage = extra; 201988d8a354b00dce7e24deee187c08a4591956ac9Steve McKay } 202988d8a354b00dce7e24deee187c08a4591956ac9Steve McKay } 20300ee050745f8c3558e7ee93d56abeb0a4ad82472Steve McKay } catch (NameNotFoundException e) { 20400ee050745f8c3558e7ee93d56abeb0a4ad82472Steve McKay // Couldn't lookup calling package info. This isn't really 20500ee050745f8c3558e7ee93d56abeb0a4ad82472Steve McKay // gonna happen, given that we're getting the name of the 20600ee050745f8c3558e7ee93d56abeb0a4ad82472Steve McKay // calling package from trusty old Activity.getCallingPackage. 20700ee050745f8c3558e7ee93d56abeb0a4ad82472Steve McKay // For that reason, we ignore this exception. 208988d8a354b00dce7e24deee187c08a4591956ac9Steve McKay } 20900ee050745f8c3558e7ee93d56abeb0a4ad82472Steve McKay return callingPackage; 210988d8a354b00dce7e24deee187c08a4591956ac9Steve McKay } 211988d8a354b00dce7e24deee187c08a4591956ac9Steve McKay 212988d8a354b00dce7e24deee187c08a4591956ac9Steve McKay /** 213988d8a354b00dce7e24deee187c08a4591956ac9Steve McKay * Returns the default directory to be presented after starting the activity. 214988d8a354b00dce7e24deee187c08a4591956ac9Steve McKay * Method can be overridden if the change of the behavior of the the child activity is needed. 215988d8a354b00dce7e24deee187c08a4591956ac9Steve McKay */ 216988d8a354b00dce7e24deee187c08a4591956ac9Steve McKay public static Uri getDefaultRootUri(Activity activity) { 217dbf09882377b4752fe45b1e2282fcbac4dcee60bBen Lin Uri defaultUri = Uri.parse(activity.getResources().getString(R.string.default_root_uri)); 218dbf09882377b4752fe45b1e2282fcbac4dcee60bBen Lin 219dbf09882377b4752fe45b1e2282fcbac4dcee60bBen Lin if (!DocumentsContract.isRootUri(activity, defaultUri)) { 220dbf09882377b4752fe45b1e2282fcbac4dcee60bBen Lin throw new RuntimeException("Default Root URI is not a valid root URI."); 221dbf09882377b4752fe45b1e2282fcbac4dcee60bBen Lin } 222dbf09882377b4752fe45b1e2282fcbac4dcee60bBen Lin 223dbf09882377b4752fe45b1e2282fcbac4dcee60bBen Lin return defaultUri; 224988d8a354b00dce7e24deee187c08a4591956ac9Steve McKay } 225988d8a354b00dce7e24deee187c08a4591956ac9Steve McKay 226741ac6fffb3ee2441569412a28a1c4f3c2160d87Aga Wronska public static boolean isHardwareKeyboardAvailable(Context context) { 227741ac6fffb3ee2441569412a28a1c4f3c2160d87Aga Wronska return context.getResources().getConfiguration().keyboard != Configuration.KEYBOARD_NOKEYS; 228741ac6fffb3ee2441569412a28a1c4f3c2160d87Aga Wronska } 229741ac6fffb3ee2441569412a28a1c4f3c2160d87Aga Wronska 230741ac6fffb3ee2441569412a28a1c4f3c2160d87Aga Wronska public static void ensureKeyboardPresent(Context context, AlertDialog dialog) { 231741ac6fffb3ee2441569412a28a1c4f3c2160d87Aga Wronska if (!isHardwareKeyboardAvailable(context)) { 2328659cbccc6fbab79fb6855abe9cb31ee8171b37eSteve McKay dialog.getWindow().setSoftInputMode( 2338659cbccc6fbab79fb6855abe9cb31ee8171b37eSteve McKay WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE); 234741ac6fffb3ee2441569412a28a1c4f3c2160d87Aga Wronska } 235741ac6fffb3ee2441569412a28a1c4f3c2160d87Aga Wronska } 236741ac6fffb3ee2441569412a28a1c4f3c2160d87Aga Wronska 237b0cbd6b0b18ea740524808b5af1f99aff628ee3bTomasz Mikolajewski /** 23817f7e5891cbe86fc6cacae045a4edd3e41f8d5eeSteve McKay * Returns true if "Documents" root should be shown. 23917f7e5891cbe86fc6cacae045a4edd3e41f8d5eeSteve McKay */ 240a0b52655668ccbe3f12ca13ced4b34118a483783Steve McKay public static boolean shouldShowDocumentsRoot(Context context) { 241317d65f8153822981ac08b944abde72a7db20104Steve McKay return context.getResources().getBoolean(R.bool.show_documents_root); 24217f7e5891cbe86fc6cacae045a4edd3e41f8d5eeSteve McKay } 24317f7e5891cbe86fc6cacae045a4edd3e41f8d5eeSteve McKay 24417f7e5891cbe86fc6cacae045a4edd3e41f8d5eeSteve McKay /* 24501996bc21961b64ef355325a9ad5c6445c734521Steve McKay * Returns true if the local/device storage root must be visible (this also hides 24601996bc21961b64ef355325a9ad5c6445c734521Steve McKay * the option to toggle visibility in the menu.) 24717f7e5891cbe86fc6cacae045a4edd3e41f8d5eeSteve McKay */ 2486525a19f46eca7fbec21a71f833436823de03da3Steve McKay public static boolean mustShowDeviceRoot(Intent intent) { 2496525a19f46eca7fbec21a71f833436823de03da3Steve McKay return intent.getBooleanExtra(DocumentsContract.EXTRA_SHOW_ADVANCED, false); 25017f7e5891cbe86fc6cacae045a4edd3e41f8d5eeSteve McKay } 25124917427f41f9e41925c4a56d0c71d85e30643dfSteve McKay 2520ce04b7a3f2c76452f855d082cd57d5e4cab9d69Steve McKay public static String getDeviceName(ContentResolver resolver) { 2530ce04b7a3f2c76452f855d082cd57d5e4cab9d69Steve McKay // We match the value supplied by ExternalStorageProvider for 2540ce04b7a3f2c76452f855d082cd57d5e4cab9d69Steve McKay // the internal storage root. 2550ce04b7a3f2c76452f855d082cd57d5e4cab9d69Steve McKay return Settings.Global.getString(resolver, Settings.Global.DEVICE_NAME); 2560ce04b7a3f2c76452f855d082cd57d5e4cab9d69Steve McKay } 2570ce04b7a3f2c76452f855d082cd57d5e4cab9d69Steve McKay 2582056205cb85d529d732638c45fe459168168e1eeGarfield, Tan public static void checkMainLoop() { 2592056205cb85d529d732638c45fe459168168e1eeGarfield, Tan if (Looper.getMainLooper() != Looper.myLooper()) { 2602056205cb85d529d732638c45fe459168168e1eeGarfield, Tan Log.e(TAG, "Calling from non-UI thread!"); 2612056205cb85d529d732638c45fe459168168e1eeGarfield, Tan } 2622056205cb85d529d732638c45fe459168168e1eeGarfield, Tan } 26385ec0d676297724f211213c7cb188839f1d3601bSteve McKay 26485ec0d676297724f211213c7cb188839f1d3601bSteve McKay public static @Nullable <T> T findView(Activity activity, int... resources) { 26585ec0d676297724f211213c7cb188839f1d3601bSteve McKay for (int id : resources) { 26685ec0d676297724f211213c7cb188839f1d3601bSteve McKay @SuppressWarnings("unchecked") 26785ec0d676297724f211213c7cb188839f1d3601bSteve McKay T r = (T) activity.findViewById(id); 26885ec0d676297724f211213c7cb188839f1d3601bSteve McKay if (r != null) { 26985ec0d676297724f211213c7cb188839f1d3601bSteve McKay return r; 27085ec0d676297724f211213c7cb188839f1d3601bSteve McKay } 27185ec0d676297724f211213c7cb188839f1d3601bSteve McKay } 27285ec0d676297724f211213c7cb188839f1d3601bSteve McKay return null; 27385ec0d676297724f211213c7cb188839f1d3601bSteve McKay } 274fefcd700d6b4cf1c4402af74c50fb0e762472901Steve McKay} 275