Shared.java revision 24917427f41f9e41925c4a56d0c71d85e30643df
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 17fefcd700d6b4cf1c4402af74c50fb0e762472901Steve McKaypackage com.android.documentsui; 18fefcd700d6b4cf1c4402af74c50fb0e762472901Steve McKay 1924917427f41f9e41925c4a56d0c71d85e30643dfSteve McKayimport android.app.Activity; 2017f7e5891cbe86fc6cacae045a4edd3e41f8d5eeSteve McKayimport android.app.AlertDialog; 21919231857d2add3afe51f06aaf41663a252c3e0eBen Kwaimport android.content.Context; 2217f7e5891cbe86fc6cacae045a4edd3e41f8d5eeSteve McKayimport android.content.Intent; 23741ac6fffb3ee2441569412a28a1c4f3c2160d87Aga Wronskaimport android.content.res.Configuration; 2417f7e5891cbe86fc6cacae045a4edd3e41f8d5eeSteve McKayimport android.provider.DocumentsContract; 2555c00e7356d9f76e7378cf7c701b9a41cb7be6daSteve McKayimport android.text.TextUtils; 268e3fd7676023738c04d099f2940a635ff0699717Ben Kwaimport android.text.format.DateUtils; 278e3fd7676023738c04d099f2940a635ff0699717Ben Kwaimport android.text.format.Time; 28741ac6fffb3ee2441569412a28a1c4f3c2160d87Aga Wronskaimport android.view.WindowManager; 296d50bcc90e6f8b3c16e23b3fc2d63f57804dd805Aga Wronska 3055c00e7356d9f76e7378cf7c701b9a41cb7be6daSteve McKayimport java.text.Collator; 31c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKayimport java.util.ArrayList; 32c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKayimport java.util.List; 33c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay 344d0255f79cc92a5675d14b20f9cdf06ecb8d7109Steve McKay/** @hide */ 35fefcd700d6b4cf1c4402af74c50fb0e762472901Steve McKaypublic final class Shared { 3655c00e7356d9f76e7378cf7c701b9a41cb7be6daSteve McKay 370af8afd3309538dec784ed0c9c35b252a8213123Steve McKay public static final String TAG = "Documents"; 380af8afd3309538dec784ed0c9c35b252a8213123Steve McKay 39543a29231a88ac332d1b1c03ccf0cb605b6aebfeBen Kwa public static final boolean DEBUG = false; 400af8afd3309538dec784ed0c9c35b252a8213123Steve McKay 41ae96780a8909476dca709b88dbae5ec9a2f0632cBen Kwa /** Intent action name to pick a copy destination. */ 42ae96780a8909476dca709b88dbae5ec9a2f0632cBen Kwa public static final String ACTION_PICK_COPY_DESTINATION = 43ae96780a8909476dca709b88dbae5ec9a2f0632cBen Kwa "com.android.documentsui.PICK_COPY_DESTINATION"; 44ae96780a8909476dca709b88dbae5ec9a2f0632cBen Kwa 45ae96780a8909476dca709b88dbae5ec9a2f0632cBen Kwa /** 4617f7e5891cbe86fc6cacae045a4edd3e41f8d5eeSteve McKay * Extra flag allowing app to be opened in productivity mode (less downloadsy). 4717f7e5891cbe86fc6cacae045a4edd3e41f8d5eeSteve McKay * Useful developers and the likes. When set to true overrides the default 4817f7e5891cbe86fc6cacae045a4edd3e41f8d5eeSteve McKay * config value of productivity_device. 4917f7e5891cbe86fc6cacae045a4edd3e41f8d5eeSteve McKay */ 5017f7e5891cbe86fc6cacae045a4edd3e41f8d5eeSteve McKay public static final String EXTRA_PRODUCTIVITY_MODE = "com.android.documentsui.PRODUCTIVITY"; 5117f7e5891cbe86fc6cacae045a4edd3e41f8d5eeSteve McKay 5217f7e5891cbe86fc6cacae045a4edd3e41f8d5eeSteve McKay /** 53ae96780a8909476dca709b88dbae5ec9a2f0632cBen Kwa * Extra boolean flag for {@link ACTION_PICK_COPY_DESTINATION}, which 54ae96780a8909476dca709b88dbae5ec9a2f0632cBen Kwa * specifies if the destination directory needs to create new directory or not. 55ae96780a8909476dca709b88dbae5ec9a2f0632cBen Kwa */ 56ae96780a8909476dca709b88dbae5ec9a2f0632cBen Kwa public static final String EXTRA_DIRECTORY_COPY = "com.android.documentsui.DIRECTORY_COPY"; 5717f7e5891cbe86fc6cacae045a4edd3e41f8d5eeSteve McKay 5817f7e5891cbe86fc6cacae045a4edd3e41f8d5eeSteve McKay /** 5917f7e5891cbe86fc6cacae045a4edd3e41f8d5eeSteve McKay * Extra flag used to store the current stack so user opens in right spot. 6017f7e5891cbe86fc6cacae045a4edd3e41f8d5eeSteve McKay */ 61af5ace5d5e3a273b151e012206efd029c2872b59Aga Wronska public static final String EXTRA_STACK = "com.android.documentsui.STACK"; 62af5ace5d5e3a273b151e012206efd029c2872b59Aga Wronska 63af5ace5d5e3a273b151e012206efd029c2872b59Aga Wronska /** 64af5ace5d5e3a273b151e012206efd029c2872b59Aga Wronska * Extra flag used to store query of type String in the bundle. 65af5ace5d5e3a273b151e012206efd029c2872b59Aga Wronska */ 66af5ace5d5e3a273b151e012206efd029c2872b59Aga Wronska public static final String EXTRA_QUERY = "query"; 67af5ace5d5e3a273b151e012206efd029c2872b59Aga Wronska 68af5ace5d5e3a273b151e012206efd029c2872b59Aga Wronska /** 69af5ace5d5e3a273b151e012206efd029c2872b59Aga Wronska * Extra flag used to store state of type State in the bundle. 70af5ace5d5e3a273b151e012206efd029c2872b59Aga Wronska */ 71af5ace5d5e3a273b151e012206efd029c2872b59Aga Wronska public static final String EXTRA_STATE = "state"; 72af5ace5d5e3a273b151e012206efd029c2872b59Aga Wronska 73af5ace5d5e3a273b151e012206efd029c2872b59Aga Wronska /** 74af5ace5d5e3a273b151e012206efd029c2872b59Aga Wronska * Extra flag used to store type of DirectoryFragment's type ResultType type in the bundle. 75af5ace5d5e3a273b151e012206efd029c2872b59Aga Wronska */ 76af5ace5d5e3a273b151e012206efd029c2872b59Aga Wronska public static final String EXTRA_TYPE = "type"; 77af5ace5d5e3a273b151e012206efd029c2872b59Aga Wronska 78af5ace5d5e3a273b151e012206efd029c2872b59Aga Wronska /** 79af5ace5d5e3a273b151e012206efd029c2872b59Aga Wronska * Extra flag used to store root of type RootInfo in the bundle. 80af5ace5d5e3a273b151e012206efd029c2872b59Aga Wronska */ 81af5ace5d5e3a273b151e012206efd029c2872b59Aga Wronska public static final String EXTRA_ROOT = "root"; 82af5ace5d5e3a273b151e012206efd029c2872b59Aga Wronska 83af5ace5d5e3a273b151e012206efd029c2872b59Aga Wronska /** 84af5ace5d5e3a273b151e012206efd029c2872b59Aga Wronska * Extra flag used to store document of DocumentInfo type in the bundle. 85af5ace5d5e3a273b151e012206efd029c2872b59Aga Wronska */ 86af5ace5d5e3a273b151e012206efd029c2872b59Aga Wronska public static final String EXTRA_DOC = "document"; 87af5ace5d5e3a273b151e012206efd029c2872b59Aga Wronska 88af5ace5d5e3a273b151e012206efd029c2872b59Aga Wronska /** 89af5ace5d5e3a273b151e012206efd029c2872b59Aga Wronska * Extra flag used to store DirectoryFragment's selection of Selection type in the bundle. 90af5ace5d5e3a273b151e012206efd029c2872b59Aga Wronska */ 91af5ace5d5e3a273b151e012206efd029c2872b59Aga Wronska public static final String EXTRA_SELECTION = "selection"; 92af5ace5d5e3a273b151e012206efd029c2872b59Aga Wronska 93af5ace5d5e3a273b151e012206efd029c2872b59Aga Wronska /** 94af5ace5d5e3a273b151e012206efd029c2872b59Aga Wronska * Extra flag used to store DirectoryFragment's search mode of boolean type in the bundle. 95af5ace5d5e3a273b151e012206efd029c2872b59Aga Wronska */ 96af5ace5d5e3a273b151e012206efd029c2872b59Aga Wronska public static final String EXTRA_SEARCH_MODE = "searchMode"; 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 /** 1092ccad1e19bb5e9308ff06c90327de99cc509f613Tomasz Mikolajewski * Maximum number of items in a Binder transaction packet. 1102ccad1e19bb5e9308ff06c90327de99cc509f613Tomasz Mikolajewski */ 1112ccad1e19bb5e9308ff06c90327de99cc509f613Tomasz Mikolajewski public static final int MAX_DOCS_IN_INTENT = 1000; 1122ccad1e19bb5e9308ff06c90327de99cc509f613Tomasz Mikolajewski 11355c00e7356d9f76e7378cf7c701b9a41cb7be6daSteve McKay private static final Collator sCollator; 11455c00e7356d9f76e7378cf7c701b9a41cb7be6daSteve McKay 11555c00e7356d9f76e7378cf7c701b9a41cb7be6daSteve McKay static { 11655c00e7356d9f76e7378cf7c701b9a41cb7be6daSteve McKay sCollator = Collator.getInstance(); 11755c00e7356d9f76e7378cf7c701b9a41cb7be6daSteve McKay sCollator.setStrength(Collator.SECONDARY); 11855c00e7356d9f76e7378cf7c701b9a41cb7be6daSteve McKay } 11955c00e7356d9f76e7378cf7c701b9a41cb7be6daSteve McKay 120919231857d2add3afe51f06aaf41663a252c3e0eBen Kwa /** 121919231857d2add3afe51f06aaf41663a252c3e0eBen Kwa * Generates a formatted quantity string. 122919231857d2add3afe51f06aaf41663a252c3e0eBen Kwa */ 123919231857d2add3afe51f06aaf41663a252c3e0eBen Kwa public static final String getQuantityString(Context context, int resourceId, int quantity) { 124919231857d2add3afe51f06aaf41663a252c3e0eBen Kwa return context.getResources().getQuantityString(resourceId, quantity, quantity); 125919231857d2add3afe51f06aaf41663a252c3e0eBen Kwa } 1268e3fd7676023738c04d099f2940a635ff0699717Ben Kwa 1278e3fd7676023738c04d099f2940a635ff0699717Ben Kwa public static String formatTime(Context context, long when) { 1288e3fd7676023738c04d099f2940a635ff0699717Ben Kwa // TODO: DateUtils should make this easier 1298e3fd7676023738c04d099f2940a635ff0699717Ben Kwa Time then = new Time(); 1308e3fd7676023738c04d099f2940a635ff0699717Ben Kwa then.set(when); 1318e3fd7676023738c04d099f2940a635ff0699717Ben Kwa Time now = new Time(); 1328e3fd7676023738c04d099f2940a635ff0699717Ben Kwa now.setToNow(); 1338e3fd7676023738c04d099f2940a635ff0699717Ben Kwa 1348e3fd7676023738c04d099f2940a635ff0699717Ben Kwa int flags = DateUtils.FORMAT_NO_NOON | DateUtils.FORMAT_NO_MIDNIGHT 1358e3fd7676023738c04d099f2940a635ff0699717Ben Kwa | DateUtils.FORMAT_ABBREV_ALL; 1368e3fd7676023738c04d099f2940a635ff0699717Ben Kwa 1378e3fd7676023738c04d099f2940a635ff0699717Ben Kwa if (then.year != now.year) { 1388e3fd7676023738c04d099f2940a635ff0699717Ben Kwa flags |= DateUtils.FORMAT_SHOW_YEAR | DateUtils.FORMAT_SHOW_DATE; 1398e3fd7676023738c04d099f2940a635ff0699717Ben Kwa } else if (then.yearDay != now.yearDay) { 1408e3fd7676023738c04d099f2940a635ff0699717Ben Kwa flags |= DateUtils.FORMAT_SHOW_DATE; 1418e3fd7676023738c04d099f2940a635ff0699717Ben Kwa } else { 1428e3fd7676023738c04d099f2940a635ff0699717Ben Kwa flags |= DateUtils.FORMAT_SHOW_TIME; 1438e3fd7676023738c04d099f2940a635ff0699717Ben Kwa } 1448e3fd7676023738c04d099f2940a635ff0699717Ben Kwa 1458e3fd7676023738c04d099f2940a635ff0699717Ben Kwa return DateUtils.formatDateTime(context, when, flags); 1468e3fd7676023738c04d099f2940a635ff0699717Ben Kwa } 1478e3fd7676023738c04d099f2940a635ff0699717Ben Kwa 148c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay /** 149c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay * A convenient way to transform any list into a (parcelable) ArrayList. 150c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay * Uses cast if possible, else creates a new list with entries from {@code list}. 151c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay */ 152c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay public static <T> ArrayList<T> asArrayList(List<T> list) { 153c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay return list instanceof ArrayList 154c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay ? (ArrayList<T>) list 155c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay : new ArrayList<T>(list); 156c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay } 15755c00e7356d9f76e7378cf7c701b9a41cb7be6daSteve McKay 15855c00e7356d9f76e7378cf7c701b9a41cb7be6daSteve McKay /** 15955c00e7356d9f76e7378cf7c701b9a41cb7be6daSteve McKay * Compare two strings against each other using system default collator in a 16006b036f0236149aa8f19a3ededf3d66ba2121a8dTomasz Mikolajewski * case-insensitive mode. Clusters strings prefixed with {@link DIR_PREFIX} 16106b036f0236149aa8f19a3ededf3d66ba2121a8dTomasz Mikolajewski * before other items. 16255c00e7356d9f76e7378cf7c701b9a41cb7be6daSteve McKay */ 16355c00e7356d9f76e7378cf7c701b9a41cb7be6daSteve McKay public static int compareToIgnoreCaseNullable(String lhs, String rhs) { 16455c00e7356d9f76e7378cf7c701b9a41cb7be6daSteve McKay final boolean leftEmpty = TextUtils.isEmpty(lhs); 16555c00e7356d9f76e7378cf7c701b9a41cb7be6daSteve McKay final boolean rightEmpty = TextUtils.isEmpty(rhs); 16655c00e7356d9f76e7378cf7c701b9a41cb7be6daSteve McKay 16755c00e7356d9f76e7378cf7c701b9a41cb7be6daSteve McKay if (leftEmpty && rightEmpty) return 0; 16855c00e7356d9f76e7378cf7c701b9a41cb7be6daSteve McKay if (leftEmpty) return -1; 16955c00e7356d9f76e7378cf7c701b9a41cb7be6daSteve McKay if (rightEmpty) return 1; 17055c00e7356d9f76e7378cf7c701b9a41cb7be6daSteve McKay 17155c00e7356d9f76e7378cf7c701b9a41cb7be6daSteve McKay return sCollator.compare(lhs, rhs); 17255c00e7356d9f76e7378cf7c701b9a41cb7be6daSteve McKay } 173741ac6fffb3ee2441569412a28a1c4f3c2160d87Aga Wronska 174741ac6fffb3ee2441569412a28a1c4f3c2160d87Aga Wronska public static boolean isHardwareKeyboardAvailable(Context context) { 175741ac6fffb3ee2441569412a28a1c4f3c2160d87Aga Wronska return context.getResources().getConfiguration().keyboard != Configuration.KEYBOARD_NOKEYS; 176741ac6fffb3ee2441569412a28a1c4f3c2160d87Aga Wronska } 177741ac6fffb3ee2441569412a28a1c4f3c2160d87Aga Wronska 178741ac6fffb3ee2441569412a28a1c4f3c2160d87Aga Wronska public static void ensureKeyboardPresent(Context context, AlertDialog dialog) { 179741ac6fffb3ee2441569412a28a1c4f3c2160d87Aga Wronska if (!isHardwareKeyboardAvailable(context)) { 180741ac6fffb3ee2441569412a28a1c4f3c2160d87Aga Wronska dialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE); 181741ac6fffb3ee2441569412a28a1c4f3c2160d87Aga Wronska } 182741ac6fffb3ee2441569412a28a1c4f3c2160d87Aga Wronska } 183741ac6fffb3ee2441569412a28a1c4f3c2160d87Aga Wronska 18464ae1f4e0236cf9ff06e19887c491bf08ee8adceAga Wronska /* 18517f7e5891cbe86fc6cacae045a4edd3e41f8d5eeSteve McKay * Returns true if app is running in "productivity mode". 18664ae1f4e0236cf9ff06e19887c491bf08ee8adceAga Wronska */ 18717f7e5891cbe86fc6cacae045a4edd3e41f8d5eeSteve McKay private static boolean isProductivityMode(Context context, Intent intent) { 18817f7e5891cbe86fc6cacae045a4edd3e41f8d5eeSteve McKay return intent.getBooleanExtra( 18917f7e5891cbe86fc6cacae045a4edd3e41f8d5eeSteve McKay Shared.EXTRA_PRODUCTIVITY_MODE, 19017f7e5891cbe86fc6cacae045a4edd3e41f8d5eeSteve McKay context.getResources().getBoolean(R.bool.productivity_device)); 19117f7e5891cbe86fc6cacae045a4edd3e41f8d5eeSteve McKay } 19217f7e5891cbe86fc6cacae045a4edd3e41f8d5eeSteve McKay 19317f7e5891cbe86fc6cacae045a4edd3e41f8d5eeSteve McKay /* 19417f7e5891cbe86fc6cacae045a4edd3e41f8d5eeSteve McKay * Returns true if "Documents" root should be shown. 19517f7e5891cbe86fc6cacae045a4edd3e41f8d5eeSteve McKay */ 19617f7e5891cbe86fc6cacae045a4edd3e41f8d5eeSteve McKay public static boolean shouldShowDocumentsRoot(Context context, Intent intent) { 19717f7e5891cbe86fc6cacae045a4edd3e41f8d5eeSteve McKay return isProductivityMode(context, intent); 19817f7e5891cbe86fc6cacae045a4edd3e41f8d5eeSteve McKay } 19917f7e5891cbe86fc6cacae045a4edd3e41f8d5eeSteve McKay 20017f7e5891cbe86fc6cacae045a4edd3e41f8d5eeSteve McKay /* 20117f7e5891cbe86fc6cacae045a4edd3e41f8d5eeSteve McKay * Returns true if device root should be shown. 20217f7e5891cbe86fc6cacae045a4edd3e41f8d5eeSteve McKay */ 20317f7e5891cbe86fc6cacae045a4edd3e41f8d5eeSteve McKay public static boolean shouldShowDeviceRoot(Context context, Intent intent) { 20417f7e5891cbe86fc6cacae045a4edd3e41f8d5eeSteve McKay return isProductivityMode(context, intent) 20517f7e5891cbe86fc6cacae045a4edd3e41f8d5eeSteve McKay || intent.getBooleanExtra(DocumentsContract.EXTRA_SHOW_ADVANCED, false); 20617f7e5891cbe86fc6cacae045a4edd3e41f8d5eeSteve McKay } 20724917427f41f9e41925c4a56d0c71d85e30643dfSteve McKay 20824917427f41f9e41925c4a56d0c71d85e30643dfSteve McKay /** 20924917427f41f9e41925c4a56d0c71d85e30643dfSteve McKay * Returns true if device root should be shown. 21024917427f41f9e41925c4a56d0c71d85e30643dfSteve McKay */ 21124917427f41f9e41925c4a56d0c71d85e30643dfSteve McKay public static boolean shouldShowFancyFeatures(Activity activity) { 21224917427f41f9e41925c4a56d0c71d85e30643dfSteve McKay Intent intent = activity.getIntent(); 21324917427f41f9e41925c4a56d0c71d85e30643dfSteve McKay return isProductivityMode(activity, intent) 21424917427f41f9e41925c4a56d0c71d85e30643dfSteve McKay || intent.getBooleanExtra(DocumentsContract.EXTRA_FANCY_FEATURES, false); 21524917427f41f9e41925c4a56d0c71d85e30643dfSteve McKay } 216fefcd700d6b4cf1c4402af74c50fb0e762472901Steve McKay} 217