1/**
2 * Copyright (C) 2016 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
17package android.support.v13.view.inputmethod;
18
19import android.content.ClipDescription;
20import android.net.Uri;
21import android.os.Build;
22import android.support.annotation.NonNull;
23import android.support.annotation.Nullable;
24import android.support.annotation.RequiresApi;
25import android.view.inputmethod.InputContentInfo;
26
27/**
28 * Helper for accessing features in InputContentInfo introduced after API level 13 in a backwards
29 * compatible fashion.
30 */
31public final class InputContentInfoCompat {
32
33    private interface InputContentInfoCompatImpl {
34        @NonNull
35        Uri getContentUri();
36
37        @NonNull
38        ClipDescription getDescription();
39
40        @Nullable
41        Uri getLinkUri();
42
43        @Nullable
44        Object getInputContentInfo();
45
46        void requestPermission();
47
48        void releasePermission();
49    }
50
51    private static final class InputContentInfoCompatBaseImpl
52            implements InputContentInfoCompatImpl {
53        @NonNull
54        private final Uri mContentUri;
55        @NonNull
56        private final ClipDescription mDescription;
57        @Nullable
58        private final Uri mLinkUri;
59
60        InputContentInfoCompatBaseImpl(@NonNull Uri contentUri,
61                @NonNull ClipDescription description, @Nullable Uri linkUri) {
62            mContentUri = contentUri;
63            mDescription = description;
64            mLinkUri = linkUri;
65        }
66
67        @NonNull
68        @Override
69        public Uri getContentUri() {
70            return mContentUri;
71        }
72
73        @NonNull
74        @Override
75        public ClipDescription getDescription() {
76            return mDescription;
77        }
78
79        @Nullable
80        @Override
81        public Uri getLinkUri() {
82            return mLinkUri;
83        }
84
85        @Nullable
86        @Override
87        public Object getInputContentInfo() {
88            return null;
89        }
90
91        @Override
92        public void requestPermission() {
93            return;
94        }
95
96        @Override
97        public void releasePermission() {
98            return;
99        }
100    }
101
102    @RequiresApi(25)
103    private static final class InputContentInfoCompatApi25Impl
104            implements InputContentInfoCompatImpl {
105        @NonNull
106        final InputContentInfo mObject;
107
108        InputContentInfoCompatApi25Impl(@NonNull Object inputContentInfo) {
109            mObject = (InputContentInfo) inputContentInfo;
110        }
111
112        InputContentInfoCompatApi25Impl(@NonNull Uri contentUri,
113                @NonNull ClipDescription description, @Nullable Uri linkUri) {
114            mObject = new InputContentInfo(contentUri, description, linkUri);
115        }
116
117        @Override
118        @NonNull
119        public Uri getContentUri() {
120            return mObject.getContentUri();
121        }
122
123        @Override
124        @NonNull
125        public ClipDescription getDescription() {
126            return mObject.getDescription();
127        }
128
129        @Override
130        @Nullable
131        public Uri getLinkUri() {
132            return mObject.getLinkUri();
133        }
134
135        @Override
136        @Nullable
137        public Object getInputContentInfo() {
138            return mObject;
139        }
140
141        @Override
142        public void requestPermission() {
143            mObject.requestPermission();
144        }
145
146        @Override
147        public void releasePermission() {
148            mObject.releasePermission();
149        }
150    }
151
152    private final InputContentInfoCompatImpl mImpl;
153
154    /**
155     * Constructs {@link InputContentInfoCompat}.
156     *
157     * @param contentUri content URI to be exported from the input method. This cannot be
158     *                   {@code null}.
159     * @param description a {@link ClipDescription} object that contains the metadata of
160     *                    {@code contentUri} such as MIME type(s). This object cannot be
161     *                    {@code null}. Also {@link ClipDescription#getLabel()} should be describing
162     *                    the content specified by {@code contentUri} for accessibility reasons.
163     * @param linkUri an optional {@code http} or {@code https} URI. The editor author may provide
164     *                a way to navigate the user to the specified web page if this is not
165     *                {@code null}.
166     */
167    public InputContentInfoCompat(@NonNull Uri contentUri,
168            @NonNull ClipDescription description, @Nullable Uri linkUri) {
169        if (Build.VERSION.SDK_INT >= 25) {
170            mImpl = new InputContentInfoCompatApi25Impl(contentUri, description, linkUri);
171        } else {
172            mImpl = new InputContentInfoCompatBaseImpl(contentUri, description, linkUri);
173        }
174    }
175
176    private InputContentInfoCompat(@NonNull InputContentInfoCompatImpl impl) {
177        mImpl = impl;
178    }
179
180    /**
181     * @return content URI with which the content can be obtained.
182     */
183    @NonNull
184    public Uri getContentUri() {
185        return mImpl.getContentUri();
186    }
187
188    /**
189     * @return {@link ClipDescription} object that contains the metadata of {@code #getContentUri()}
190     * such as MIME type(s). {@link ClipDescription#getLabel()} can be used for accessibility
191     * purpose.
192     */
193    @NonNull
194    public ClipDescription getDescription() {
195        return mImpl.getDescription();
196    }
197
198    /**
199     * @return an optional {@code http} or {@code https} URI that is related to this content.
200     */
201    @Nullable
202    public Uri getLinkUri() {
203        return mImpl.getLinkUri();
204    }
205
206    /**
207     * Creates an instance from a framework android.view.inputmethod.InputContentInfo object.
208     *
209     * <p>This method always returns {@code null} on API &lt;= 24.</p>
210     *
211     * @param inputContentInfo an android.view.inputmethod.InputContentInfo object, or {@code null}
212     *                         if none.
213     * @return an equivalent {@link InputContentInfoCompat} object, or {@code null} if not
214     * supported.
215     */
216    @Nullable
217    public static InputContentInfoCompat wrap(@Nullable Object inputContentInfo) {
218        if (inputContentInfo == null) {
219            return null;
220        }
221        if (Build.VERSION.SDK_INT < 25) {
222            return null;
223        }
224        return new InputContentInfoCompat(new InputContentInfoCompatApi25Impl(inputContentInfo));
225    }
226
227    /**
228     * Gets the underlying framework android.view.inputmethod.InputContentInfo object.
229     *
230     * <p>This method always returns {@code null} on API &lt;= 24.</p>
231     *
232     * @return an equivalent android.view.inputmethod.InputContentInfo object, or {@code null} if
233     * not supported.
234     */
235    @Nullable
236    public Object unwrap() {
237        return mImpl.getInputContentInfo();
238    }
239
240    /**
241     * Requests a temporary read-only access permission for content URI associated with this object.
242     *
243     * <p>Does nothing if the temporary permission is already granted.</p>
244     */
245    public void requestPermission() {
246        mImpl.requestPermission();
247    }
248
249    /**
250     * Releases a temporary read-only access permission for content URI associated with this object.
251     *
252     * <p>Does nothing if the temporary permission is not granted.</p>
253     */
254    public void releasePermission() {
255        mImpl.releasePermission();
256    }
257}
258