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