1 /* 2 * Copyright (C) 2015 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.documentsui; 18 19 import android.app.Activity; 20 import android.app.AlertDialog; 21 import android.content.Context; 22 import android.content.Intent; 23 import android.content.res.Configuration; 24 import android.provider.DocumentsContract; 25 import android.text.TextUtils; 26 import android.text.format.DateUtils; 27 import android.text.format.Time; 28 import android.view.WindowManager; 29 30 import java.text.Collator; 31 import java.util.ArrayList; 32 import java.util.List; 33 34 /** @hide */ 35 public final class Shared { 36 37 public static final String TAG = "Documents"; 38 39 public static final boolean DEBUG = false; 40 41 /** Intent action name to pick a copy destination. */ 42 public static final String ACTION_PICK_COPY_DESTINATION = 43 "com.android.documentsui.PICK_COPY_DESTINATION"; 44 45 /** 46 * Extra flag allowing app to be opened in productivity mode (less downloadsy). 47 * Useful developers and the likes. When set to true overrides the default 48 * config value of productivity_device. 49 */ 50 public static final String EXTRA_PRODUCTIVITY_MODE = "com.android.documentsui.PRODUCTIVITY"; 51 52 /** 53 * Extra boolean flag for {@link ACTION_PICK_COPY_DESTINATION}, which 54 * specifies if the destination directory needs to create new directory or not. 55 */ 56 public static final String EXTRA_DIRECTORY_COPY = "com.android.documentsui.DIRECTORY_COPY"; 57 58 /** 59 * Extra flag used to store the current stack so user opens in right spot. 60 */ 61 public static final String EXTRA_STACK = "com.android.documentsui.STACK"; 62 63 /** 64 * Extra flag used to store query of type String in the bundle. 65 */ 66 public static final String EXTRA_QUERY = "query"; 67 68 /** 69 * Extra flag used to store state of type State in the bundle. 70 */ 71 public static final String EXTRA_STATE = "state"; 72 73 /** 74 * Extra flag used to store type of DirectoryFragment's type ResultType type in the bundle. 75 */ 76 public static final String EXTRA_TYPE = "type"; 77 78 /** 79 * Extra flag used to store root of type RootInfo in the bundle. 80 */ 81 public static final String EXTRA_ROOT = "root"; 82 83 /** 84 * Extra flag used to store document of DocumentInfo type in the bundle. 85 */ 86 public static final String EXTRA_DOC = "document"; 87 88 /** 89 * Extra flag used to store DirectoryFragment's selection of Selection type in the bundle. 90 */ 91 public static final String EXTRA_SELECTION = "selection"; 92 93 /** 94 * Extra flag used to store DirectoryFragment's search mode of boolean type in the bundle. 95 */ 96 public static final String EXTRA_SEARCH_MODE = "searchMode"; 97 98 /** 99 * Extra flag used to store DirectoryFragment's ignore state of boolean type in the bundle. 100 */ 101 public static final String EXTRA_IGNORE_STATE = "ignoreState"; 102 103 /** 104 * Extra for an Intent for enabling performance benchmark. Used only by tests. 105 */ 106 public static final String EXTRA_BENCHMARK = "com.android.documentsui.benchmark"; 107 108 /** 109 * Maximum number of items in a Binder transaction packet. 110 */ 111 public static final int MAX_DOCS_IN_INTENT = 1000; 112 113 private static final Collator sCollator; 114 115 static { 116 sCollator = Collator.getInstance(); 117 sCollator.setStrength(Collator.SECONDARY); 118 } 119 120 /** 121 * Generates a formatted quantity string. 122 */ getQuantityString(Context context, int resourceId, int quantity)123 public static final String getQuantityString(Context context, int resourceId, int quantity) { 124 return context.getResources().getQuantityString(resourceId, quantity, quantity); 125 } 126 formatTime(Context context, long when)127 public static String formatTime(Context context, long when) { 128 // TODO: DateUtils should make this easier 129 Time then = new Time(); 130 then.set(when); 131 Time now = new Time(); 132 now.setToNow(); 133 134 int flags = DateUtils.FORMAT_NO_NOON | DateUtils.FORMAT_NO_MIDNIGHT 135 | DateUtils.FORMAT_ABBREV_ALL; 136 137 if (then.year != now.year) { 138 flags |= DateUtils.FORMAT_SHOW_YEAR | DateUtils.FORMAT_SHOW_DATE; 139 } else if (then.yearDay != now.yearDay) { 140 flags |= DateUtils.FORMAT_SHOW_DATE; 141 } else { 142 flags |= DateUtils.FORMAT_SHOW_TIME; 143 } 144 145 return DateUtils.formatDateTime(context, when, flags); 146 } 147 148 /** 149 * A convenient way to transform any list into a (parcelable) ArrayList. 150 * Uses cast if possible, else creates a new list with entries from {@code list}. 151 */ asArrayList(List<T> list)152 public static <T> ArrayList<T> asArrayList(List<T> list) { 153 return list instanceof ArrayList 154 ? (ArrayList<T>) list 155 : new ArrayList<T>(list); 156 } 157 158 /** 159 * Compare two strings against each other using system default collator in a 160 * case-insensitive mode. Clusters strings prefixed with {@link DIR_PREFIX} 161 * before other items. 162 */ compareToIgnoreCaseNullable(String lhs, String rhs)163 public static int compareToIgnoreCaseNullable(String lhs, String rhs) { 164 final boolean leftEmpty = TextUtils.isEmpty(lhs); 165 final boolean rightEmpty = TextUtils.isEmpty(rhs); 166 167 if (leftEmpty && rightEmpty) return 0; 168 if (leftEmpty) return -1; 169 if (rightEmpty) return 1; 170 171 return sCollator.compare(lhs, rhs); 172 } 173 isHardwareKeyboardAvailable(Context context)174 public static boolean isHardwareKeyboardAvailable(Context context) { 175 return context.getResources().getConfiguration().keyboard != Configuration.KEYBOARD_NOKEYS; 176 } 177 ensureKeyboardPresent(Context context, AlertDialog dialog)178 public static void ensureKeyboardPresent(Context context, AlertDialog dialog) { 179 if (!isHardwareKeyboardAvailable(context)) { 180 dialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE); 181 } 182 } 183 184 /* 185 * Returns true if app is running in "productivity mode". 186 */ isProductivityMode(Context context, Intent intent)187 private static boolean isProductivityMode(Context context, Intent intent) { 188 return intent.getBooleanExtra( 189 Shared.EXTRA_PRODUCTIVITY_MODE, 190 context.getResources().getBoolean(R.bool.productivity_device)); 191 } 192 193 /* 194 * Returns true if "Documents" root should be shown. 195 */ shouldShowDocumentsRoot(Context context, Intent intent)196 public static boolean shouldShowDocumentsRoot(Context context, Intent intent) { 197 return isProductivityMode(context, intent); 198 } 199 200 /* 201 * Returns true if device root should be shown. 202 */ shouldShowDeviceRoot(Context context, Intent intent)203 public static boolean shouldShowDeviceRoot(Context context, Intent intent) { 204 return isProductivityMode(context, intent) 205 || intent.getBooleanExtra(DocumentsContract.EXTRA_SHOW_ADVANCED, false); 206 } 207 208 /** 209 * Returns true if device root should be shown. 210 */ shouldShowFancyFeatures(Activity activity)211 public static boolean shouldShowFancyFeatures(Activity activity) { 212 Intent intent = activity.getIntent(); 213 return isProductivityMode(activity, intent) 214 || intent.getBooleanExtra(DocumentsContract.EXTRA_FANCY_FEATURES, false); 215 } 216 } 217