Home | History | Annotate | Download | only in inputmethod
      1 /*
      2  * Copyright (C) 2016 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
      5  * use this file except in compliance with the License. You may obtain a copy of
      6  * 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, WITHOUT
     12  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
     13  * License for the specific language governing permissions and limitations under
     14  * the License.
     15  */
     16 
     17 package android.view.inputmethod;
     18 
     19 import android.annotation.NonNull;
     20 import android.annotation.Nullable;
     21 import android.content.ClipDescription;
     22 import android.net.Uri;
     23 import android.os.Parcel;
     24 import android.os.Parcelable;
     25 import android.os.RemoteException;
     26 
     27 import com.android.internal.inputmethod.IInputContentUriToken;
     28 
     29 import java.security.InvalidParameterException;
     30 
     31 /**
     32  * A container object with which input methods can send content files to the target application.
     33  */
     34 public final class InputContentInfo implements Parcelable {
     35 
     36     @NonNull
     37     private final Uri mContentUri;
     38     @NonNull
     39     private final ClipDescription mDescription;
     40     @Nullable
     41     private final Uri mLinkUri;
     42     @NonNull
     43     private IInputContentUriToken mUriToken;
     44 
     45     /**
     46      * Constructs {@link InputContentInfo} object only with mandatory data.
     47      *
     48      * @param contentUri Content URI to be exported from the input method.
     49      * This cannot be {@code null}.
     50      * @param description A {@link ClipDescription} object that contains the metadata of
     51      * {@code contentUri} such as MIME type(s). This object cannot be {@code null}. Also
     52      * {@link ClipDescription#getLabel()} should be describing the content specified by
     53      * {@code contentUri} for accessibility reasons.
     54      */
     55     public InputContentInfo(@NonNull Uri contentUri, @NonNull ClipDescription description) {
     56         this(contentUri, description, null /* link Uri */);
     57     }
     58 
     59     /**
     60      * Constructs {@link InputContentInfo} object with additional link URI.
     61      *
     62      * @param contentUri Content URI to be exported from the input method.
     63      * This cannot be {@code null}.
     64      * @param description A {@link ClipDescription} object that contains the metadata of
     65      * {@code contentUri} such as MIME type(s). This object cannot be {@code null}. Also
     66      * {@link ClipDescription#getLabel()} should be describing the content specified by
     67      * {@code contentUri} for accessibility reasons.
     68      * @param linkUri An optional {@code http} or {@code https} URI. The editor author may provide
     69      * a way to navigate the user to the specified web page if this is not {@code null}.
     70      * @throws InvalidParameterException if any invalid parameter is specified.
     71      */
     72     public InputContentInfo(@NonNull Uri contentUri, @NonNull ClipDescription description,
     73             @Nullable Uri linkUri) {
     74         validateInternal(contentUri, description, linkUri, true /* throwException */);
     75         mContentUri = contentUri;
     76         mDescription = description;
     77         mLinkUri = linkUri;
     78     }
     79 
     80     /**
     81      * @return {@code true} if all the fields are valid.
     82      * @hide
     83      */
     84     public boolean validate() {
     85         return validateInternal(mContentUri, mDescription, mLinkUri, false /* throwException */);
     86     }
     87 
     88     /**
     89      * Constructs {@link InputContentInfo} object with additional link URI.
     90      *
     91      * @param contentUri Content URI to be exported from the input method.
     92      * This cannot be {@code null}.
     93      * @param description A {@link ClipDescription} object that contains the metadata of
     94      * {@code contentUri} such as MIME type(s). This object cannot be {@code null}. Also
     95      * {@link ClipDescription#getLabel()} should be describing the content specified by
     96      * {@code contentUri} for accessibility reasons.
     97      * @param linkUri An optional {@code http} or {@code https} URI. The editor author may provide
     98      * a way to navigate the user to the specified web page if this is not {@code null}.
     99      * @param throwException {@code true} if this method should throw an
    100      * {@link InvalidParameterException}.
    101      * @throws InvalidParameterException if any invalid parameter is specified.
    102      */
    103     private static boolean validateInternal(@NonNull Uri contentUri,
    104             @NonNull ClipDescription description, @Nullable Uri linkUri, boolean throwException) {
    105         if (contentUri == null) {
    106             if (throwException) {
    107                 throw new NullPointerException("contentUri");
    108             }
    109             return false;
    110         }
    111         if (description == null) {
    112             if (throwException) {
    113                 throw new NullPointerException("description");
    114             }
    115             return false;
    116         }
    117         final String contentUriScheme = contentUri.getScheme();
    118         if (!"content".equals(contentUriScheme)) {
    119             if (throwException) {
    120                 throw new InvalidParameterException("contentUri must have content scheme");
    121             }
    122             return false;
    123         }
    124         if (linkUri != null) {
    125             final String scheme = linkUri.getScheme();
    126             if (scheme == null ||
    127                     (!scheme.equalsIgnoreCase("http") && !scheme.equalsIgnoreCase("https"))) {
    128                 if (throwException) {
    129                     throw new InvalidParameterException(
    130                             "linkUri must have either http or https scheme");
    131                 }
    132                 return false;
    133             }
    134         }
    135         return true;
    136     }
    137 
    138     /**
    139      * @return Content URI with which the content can be obtained.
    140      */
    141     @NonNull
    142     public Uri getContentUri() { return mContentUri; }
    143 
    144     /**
    145      * @return {@link ClipDescription} object that contains the metadata of {@code #getContentUri()}
    146      * such as MIME type(s). {@link ClipDescription#getLabel()} can be used for accessibility
    147      * purpose.
    148      */
    149     @NonNull
    150     public ClipDescription getDescription() { return mDescription; }
    151 
    152     /**
    153      * @return An optional {@code http} or {@code https} URI that is related to this content.
    154      */
    155     @Nullable
    156     public Uri getLinkUri() { return mLinkUri; }
    157 
    158     void setUriToken(IInputContentUriToken token) {
    159         if (mUriToken != null) {
    160             throw new IllegalStateException("URI token is already set");
    161         }
    162         mUriToken = token;
    163     }
    164 
    165     /**
    166      * Requests a temporary read-only access permission for content URI associated with this object.
    167      *
    168      * <p>Does nothing if the temporary permission is already granted.</p>
    169      */
    170     public void requestPermission() {
    171         if (mUriToken == null) {
    172             return;
    173         }
    174         try {
    175             mUriToken.take();
    176         } catch (RemoteException e) {
    177             e.rethrowFromSystemServer();
    178         }
    179     }
    180 
    181     /**
    182      * Releases a temporary read-only access permission for content URI associated with this object.
    183      *
    184      * <p>Does nothing if the temporary permission is not granted.</p>
    185      */
    186     public void releasePermission() {
    187         if (mUriToken == null) {
    188             return;
    189         }
    190         try {
    191             mUriToken.release();
    192         } catch (RemoteException e) {
    193             e.rethrowFromSystemServer();
    194         }
    195     }
    196 
    197     /**
    198      * Used to package this object into a {@link Parcel}.
    199      *
    200      * @param dest The {@link Parcel} to be written.
    201      * @param flags The flags used for parceling.
    202      */
    203     @Override
    204     public void writeToParcel(Parcel dest, int flags) {
    205         Uri.writeToParcel(dest, mContentUri);
    206         mDescription.writeToParcel(dest, flags);
    207         Uri.writeToParcel(dest, mLinkUri);
    208         if (mUriToken != null) {
    209             dest.writeInt(1);
    210             dest.writeStrongBinder(mUriToken.asBinder());
    211         } else {
    212             dest.writeInt(0);
    213         }
    214     }
    215 
    216     private InputContentInfo(@NonNull Parcel source) {
    217         mContentUri = Uri.CREATOR.createFromParcel(source);
    218         mDescription = ClipDescription.CREATOR.createFromParcel(source);
    219         mLinkUri = Uri.CREATOR.createFromParcel(source);
    220         if (source.readInt() == 1) {
    221             mUriToken = IInputContentUriToken.Stub.asInterface(source.readStrongBinder());
    222         } else {
    223             mUriToken = null;
    224         }
    225     }
    226 
    227     /**
    228      * Used to make this class parcelable.
    229      */
    230     public static final Parcelable.Creator<InputContentInfo> CREATOR
    231             = new Parcelable.Creator<InputContentInfo>() {
    232         @Override
    233         public InputContentInfo createFromParcel(Parcel source) {
    234             return new InputContentInfo(source);
    235         }
    236 
    237         @Override
    238         public InputContentInfo[] newArray(int size) {
    239             return new InputContentInfo[size];
    240         }
    241     };
    242 
    243     /**
    244      * {@inheritDoc}
    245      */
    246     @Override
    247     public int describeContents() {
    248         return 0;
    249     }
    250 }
    251