Home | History | Annotate | Download | only in util
      1 /*
      2  * Copyright (C) 2014 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.tv.settings.util;
     18 
     19 import android.content.ContentResolver;
     20 import android.content.Context;
     21 import android.content.Intent.ShortcutIconResource;
     22 import android.content.pm.PackageManager.NameNotFoundException;
     23 import android.content.res.Resources;
     24 import android.graphics.drawable.Drawable;
     25 import android.net.Uri;
     26 import android.text.TextUtils;
     27 
     28 /**
     29  * Utilities for working with URIs.
     30  */
     31 public final class UriUtils {
     32 
     33     private static final String SCHEME_SHORTCUT_ICON_RESOURCE = "shortcut.icon.resource";
     34     private static final String SCHEME_DELIMITER = "://";
     35     private static final String URI_PATH_DELIMITER = "/";
     36     private static final String URI_PACKAGE_DELIMITER = ":";
     37     private static final String HTTP_PREFIX = "http";
     38     private static final String HTTPS_PREFIX = "https";
     39     private static final String SCHEME_ACCOUNT_IMAGE = "image.account";
     40     private static final String ACCOUNT_IMAGE_CHANGE_NOTIFY_URI = "change_notify_uri";
     41     private static final String DETAIL_DIALOG_URI_DIALOG_TITLE = "detail_dialog_title";
     42     private static final String DETAIL_DIALOG_URI_DIALOG_DESCRIPTION = "detail_dialog_description";
     43     private static final String DETAIL_DIALOG_URI_DIALOG_ACTION_START_INDEX =
     44             "detail_dialog_action_start_index";
     45     private static final String DETAIL_DIALOG_URI_DIALOG_ACTION_START_NAME =
     46             "detail_dialog_action_start_name";
     47 
     48     /**
     49      * Non instantiable.
     50      */
     51     private UriUtils() {}
     52 
     53     /**
     54      * get resource uri representation for a resource of a package
     55      */
     56     public static String getAndroidResourceUri(Context context, int resourceId) {
     57         return getAndroidResourceUri(context.getResources(), resourceId);
     58     }
     59 
     60     /**
     61      * get resource uri representation for a resource
     62      */
     63     public static String getAndroidResourceUri(Resources resources, int resourceId) {
     64         return ContentResolver.SCHEME_ANDROID_RESOURCE
     65                 + SCHEME_DELIMITER + resources.getResourceName(resourceId)
     66                         .replace(URI_PACKAGE_DELIMITER, URI_PATH_DELIMITER);
     67     }
     68 
     69     /**
     70      * load drawable from resource
     71      * TODO: move to a separate class to handle bitmap and drawables
     72      */
     73     public static Drawable getDrawable(Context context, ShortcutIconResource r)
     74             throws NameNotFoundException {
     75         Resources resources = context.getPackageManager().getResourcesForApplication(r.packageName);
     76         if (resources == null) {
     77             return null;
     78         }
     79         final int id = resources.getIdentifier(r.resourceName, null, null);
     80         return resources.getDrawable(id);
     81     }
     82 
     83     /**
     84      * Gets a URI with short cut icon scheme.
     85      */
     86     public static Uri getShortcutIconResourceUri(ShortcutIconResource iconResource) {
     87         return Uri.parse(SCHEME_SHORTCUT_ICON_RESOURCE + SCHEME_DELIMITER + iconResource.packageName
     88                 + URI_PATH_DELIMITER
     89                 + iconResource.resourceName.replace(URI_PACKAGE_DELIMITER, URI_PATH_DELIMITER));
     90     }
     91 
     92     /**
     93      * Gets a URI with scheme = {@link ContentResolver#SCHEME_ANDROID_RESOURCE}.
     94      */
     95     public static Uri getAndroidResourceUri(String resourceName) {
     96         Uri uri = Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + SCHEME_DELIMITER
     97                 + resourceName.replace(URI_PACKAGE_DELIMITER, URI_PATH_DELIMITER));
     98         return uri;
     99     }
    100 
    101     /**
    102      * Checks if the URI refers to an Android resource.
    103      */
    104     public static boolean isAndroidResourceUri(Uri uri) {
    105         return ContentResolver.SCHEME_ANDROID_RESOURCE.equals(uri.getScheme());
    106     }
    107 
    108     /**
    109      * Gets a URI with the account image scheme.
    110      */
    111     public static Uri getAccountImageUri(String accountName) {
    112         Uri uri = Uri.parse(SCHEME_ACCOUNT_IMAGE + SCHEME_DELIMITER + accountName);
    113         return uri;
    114     }
    115 
    116     /**
    117      * Gets a URI with the account image scheme, and specifying an URI to be
    118      * used in notifyChange() when the image pointed to by the returned URI is
    119      * updated.
    120      */
    121     public static Uri getAccountImageUri(String accountName, Uri changeNotifyUri) {
    122         Uri uri = Uri.parse(SCHEME_ACCOUNT_IMAGE + SCHEME_DELIMITER + accountName);
    123         if (changeNotifyUri != null) {
    124             uri = uri.buildUpon().appendQueryParameter(ACCOUNT_IMAGE_CHANGE_NOTIFY_URI,
    125                     changeNotifyUri.toString()).build();
    126         }
    127         return uri;
    128     }
    129 
    130     /**
    131      * Checks if the URI refers to an account image.
    132      */
    133     public static boolean isAccountImageUri(Uri uri) {
    134         return uri == null ? false : SCHEME_ACCOUNT_IMAGE.equals(uri.getScheme());
    135     }
    136 
    137     public static String getAccountName(Uri uri) {
    138         if (isAccountImageUri(uri)) {
    139             String accountName = uri.getAuthority() + uri.getPath();
    140             return accountName;
    141         } else {
    142             throw new IllegalArgumentException("Invalid account image URI. " + uri);
    143         }
    144     }
    145 
    146     public static Uri getAccountImageChangeNotifyUri(Uri uri) {
    147         if (isAccountImageUri(uri)) {
    148             String notifyUri = uri.getQueryParameter(ACCOUNT_IMAGE_CHANGE_NOTIFY_URI);
    149             if (notifyUri == null) {
    150                 return null;
    151             } else {
    152                 return Uri.parse(notifyUri);
    153             }
    154         } else {
    155             throw new IllegalArgumentException("Invalid account image URI. " + uri);
    156         }
    157     }
    158 
    159     /**
    160      * Returns {@code true} if the URI refers to a content URI which can be opened via
    161      * {@link ContentResolver#openInputStream(Uri)}.
    162      */
    163     public static boolean isContentUri(Uri uri) {
    164         return ContentResolver.SCHEME_CONTENT.equals(uri.getScheme()) ||
    165                 ContentResolver.SCHEME_FILE.equals(uri.getScheme());
    166     }
    167 
    168     /**
    169      * Checks if the URI refers to an shortcut icon resource.
    170      */
    171     public static boolean isShortcutIconResourceUri(Uri uri) {
    172         return SCHEME_SHORTCUT_ICON_RESOURCE.equals(uri.getScheme());
    173     }
    174 
    175     /**
    176      * Creates a shortcut icon resource object from an Android resource URI.
    177      */
    178     public static ShortcutIconResource getIconResource(Uri uri) {
    179         if(isAndroidResourceUri(uri)) {
    180             ShortcutIconResource iconResource = new ShortcutIconResource();
    181             iconResource.packageName = uri.getAuthority();
    182             // Trim off the scheme + 3 extra for "://", then replace the first "/" with a ":"
    183             iconResource.resourceName = uri.toString().substring(
    184                     ContentResolver.SCHEME_ANDROID_RESOURCE.length() + SCHEME_DELIMITER.length())
    185                     .replaceFirst(URI_PATH_DELIMITER, URI_PACKAGE_DELIMITER);
    186             return iconResource;
    187         } else if(isShortcutIconResourceUri(uri)) {
    188             ShortcutIconResource iconResource = new ShortcutIconResource();
    189             iconResource.packageName = uri.getAuthority();
    190             iconResource.resourceName = uri.toString().substring(
    191                     SCHEME_SHORTCUT_ICON_RESOURCE.length() + SCHEME_DELIMITER.length()
    192                     + iconResource.packageName.length() + URI_PATH_DELIMITER.length())
    193                     .replaceFirst(URI_PATH_DELIMITER, URI_PACKAGE_DELIMITER);
    194             return iconResource;
    195         } else {
    196             throw new IllegalArgumentException("Invalid resource URI. " + uri);
    197         }
    198     }
    199 
    200     /**
    201      * Returns {@code true} if this is a web URI.
    202      */
    203     public static boolean isWebUri(Uri resourceUri) {
    204         String scheme = resourceUri.getScheme() == null ? null
    205                 : resourceUri.getScheme().toLowerCase();
    206         return HTTP_PREFIX.equals(scheme) || HTTPS_PREFIX.equals(scheme);
    207     }
    208 
    209     /**
    210      * Build a Uri for canvas details subactions dialog given content uri and optional parameters.
    211      * @param uri the subactions ContentUri
    212      * @param dialogTitle the custom subactions dialog title. If the value is null, canvas will
    213      *        fall back to use previous action's name as the subactions dialog title.
    214      * @param dialogDescription the custom subactions dialog description. If the value is null,
    215      *        canvas will fall back to use previous action's subname as the subactions dialog
    216      *        description.
    217      * @return
    218      */
    219     public static Uri getSubactionDialogUri(Uri uri, String dialogTitle, String dialogDescription) {
    220         return getSubactionDialogUri(uri, dialogTitle, dialogDescription, null, -1);
    221     }
    222 
    223     /**
    224      * Build a Uri for canvas details subactions dialog given content uri and optional parameters.
    225      * @param uri the subactions ContentUri
    226      * @param dialogTitle the custom subactions dialog title. If the value is null, canvas will
    227      *        fall back to use previous action's name as the subactions dialog title.
    228      * @param dialogDescription the custom subactions dialog description. If the value is null,
    229      *        canvas will fall back to use previous action's subname as the subactions dialog
    230      *        description.
    231      * @param startIndex the focused action in actions list when started.
    232      * @return
    233      */
    234     public static Uri getSubactionDialogUri(Uri uri, String dialogTitle, String dialogDescription,
    235             int startIndex) {
    236         return getSubactionDialogUri(uri, dialogTitle, dialogDescription, null, startIndex);
    237     }
    238 
    239     /**
    240      * Build a Uri for canvas details subactions dialog given content uri and optional parameters.
    241      * @param uri the subactions ContentUri
    242      * @param dialogTitle the custom subactions dialog title. If the value is null, canvas will
    243      *        fall back to use previous action's name as the subactions dialog title.
    244      * @param dialogDescription the custom subactions dialog description. If the value is null,
    245      *        canvas will fall back to use previous action's subname as the subactions dialog
    246      *        description.
    247      * @param startName the name of action that is focused in actions list when started.
    248      * @return
    249      */
    250     public static Uri getSubactionDialogUri(Uri uri, String dialogTitle, String dialogDescription,
    251             String startName) {
    252         return getSubactionDialogUri(uri, dialogTitle, dialogDescription, startName, -1);
    253     }
    254 
    255     /**
    256      * Build a Uri for canvas details subactions dialog given content uri and optional parameters.
    257      * @param uri the subactions ContentUri
    258      * @param dialogTitle the custom subactions dialog title. If the value is null, canvas will
    259      *        fall back to use previous action's name as the subactions dialog title.
    260      * @param dialogDescription the custom subactions dialog description. If the value is null,
    261      *        canvas will fall back to use previous action's subname as the subactions dialog
    262      *        description.
    263      * @param startIndex the focused action in actions list when started.
    264      * @param startName the name of action that is focused in actions list when started. startName
    265      * takes priority over start index.
    266      * @return
    267      */
    268     public static Uri getSubactionDialogUri(Uri uri, String dialogTitle, String dialogDescription,
    269             String startName, int startIndex) {
    270         if (uri == null || !isContentUri(uri)) {
    271             // If given uri is null, or it is not of contentUri type, return null.
    272             return null;
    273         }
    274 
    275         Uri.Builder builder = uri.buildUpon();
    276         if (!TextUtils.isEmpty(dialogTitle)) {
    277             builder.appendQueryParameter(DETAIL_DIALOG_URI_DIALOG_TITLE, dialogTitle);
    278         }
    279 
    280         if (!TextUtils.isEmpty(DETAIL_DIALOG_URI_DIALOG_DESCRIPTION)) {
    281             builder.appendQueryParameter(DETAIL_DIALOG_URI_DIALOG_DESCRIPTION, dialogDescription);
    282         }
    283 
    284         if (startIndex != -1) {
    285             builder.appendQueryParameter(DETAIL_DIALOG_URI_DIALOG_ACTION_START_INDEX,
    286                     Integer.toString(startIndex));
    287         }
    288 
    289         if (!TextUtils.isEmpty(startName)) {
    290             builder.appendQueryParameter(DETAIL_DIALOG_URI_DIALOG_ACTION_START_NAME, startName);
    291         }
    292 
    293         return builder.build();
    294     }
    295 
    296     /**
    297      * Get subaction dialog title parameter from URI
    298      * @param uri ContentUri for canvas details subactions
    299      * @return custom dialog title if this parameter is available in URI. Otherwise, return null.
    300      */
    301     public static String getSubactionDialogTitle(Uri uri) {
    302         if (uri == null || !isContentUri(uri)) {
    303             return null;
    304         }
    305 
    306         return uri.getQueryParameter(DETAIL_DIALOG_URI_DIALOG_TITLE);
    307     }
    308 
    309     /**
    310      * Get subaction dialog description parameter from URI
    311      * @param uri ContentUri for canvas details subactions
    312      * @return custom dialog description if this parameter is available in URI.
    313      * Otherwise, return null.
    314      */
    315     public static String getSubactionDialogDescription(Uri uri) {
    316         if (uri == null || !isContentUri(uri)) {
    317             return null;
    318         }
    319 
    320         return uri.getQueryParameter(DETAIL_DIALOG_URI_DIALOG_DESCRIPTION);
    321     }
    322 
    323     /**
    324      * Get subaction dialog action list focused index when started from URI
    325      * @param uri ContentUri for canvas details subactions
    326      * @return action starting index if this parameter is available in URI. Otherwise, return -1.
    327      */
    328     public static int getSubactionDialogActionStartIndex(Uri uri) {
    329         if (uri == null || !isContentUri(uri)) {
    330             return -1;
    331         }
    332 
    333         String startIndexStr = uri.getQueryParameter(DETAIL_DIALOG_URI_DIALOG_ACTION_START_INDEX);
    334         if (!TextUtils.isEmpty(startIndexStr) && TextUtils.isDigitsOnly(startIndexStr)) {
    335             return Integer.parseInt(startIndexStr);
    336         } else {
    337             return -1;
    338         }
    339     }
    340 
    341     /**
    342      * Get subaction dialog action list focused action name when started from URI
    343      * @param uri ContentUri for canvas details subactions
    344      * @return that name of starting action if this parameter is available in URI.
    345      * Otherwise, return null.
    346      */
    347     public static String getSubactionDialogActionStartName(Uri uri) {
    348         if (uri == null || !isContentUri(uri)) {
    349             return null;
    350         }
    351 
    352         return uri.getQueryParameter(DETAIL_DIALOG_URI_DIALOG_ACTION_START_NAME);
    353     }
    354 }
    355