| /* | |
| * Copyright (C) 2016 The Android Open Source Project | |
| * | |
| * Licensed under the Apache License, Version 2.0 (the "License"); | |
| * you may not use this file except in compliance with the License. | |
| * You may obtain a copy of the License at | |
| * | |
| * http://www.apache.org/licenses/LICENSE-2.0 | |
| * | |
| * Unless required by applicable law or agreed to in writing, software | |
| * distributed under the License is distributed on an "AS IS" BASIS, | |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| * See the License for the specific language governing permissions and | |
| * limitations under the License | |
| */ | |
| package com.example.android.commitcontent.app; | |
| import android.support.v13.view.inputmethod.EditorInfoCompat; | |
| import android.support.v13.view.inputmethod.InputConnectionCompat; | |
| import android.support.v13.view.inputmethod.InputContentInfoCompat; | |
| import android.app.Activity; | |
| import android.graphics.Color; | |
| import android.net.Uri; | |
| import android.os.Bundle; | |
| import android.os.Parcelable; | |
| import android.text.TextUtils; | |
| import android.util.Log; | |
| import android.view.inputmethod.EditorInfo; | |
| import android.view.inputmethod.InputConnection; | |
| import android.webkit.WebView; | |
| import android.widget.EditText; | |
| import android.widget.LinearLayout; | |
| import android.widget.TextView; | |
| import java.util.ArrayList; | |
| import java.util.Arrays; | |
| public class MainActivity extends Activity { | |
| private static final String INPUT_CONTENT_INFO_KEY = "COMMIT_CONTENT_INPUT_CONTENT_INFO"; | |
| private static final String COMMIT_CONTENT_FLAGS_KEY = "COMMIT_CONTENT_FLAGS"; | |
| private static String TAG = "CommitContentSupport"; | |
| private WebView mWebView; | |
| private TextView mLabel; | |
| private TextView mContentUri; | |
| private TextView mLinkUri; | |
| private TextView mMimeTypes; | |
| private TextView mFlags; | |
| private InputContentInfoCompat mCurrentInputContentInfo; | |
| private int mCurrentFlags; | |
| @Override | |
| public void onCreate(Bundle savedInstanceState) { | |
| super.onCreate(savedInstanceState); | |
| setContentView(R.layout.commit_content); | |
| final LinearLayout layout = | |
| (LinearLayout) findViewById(R.id.commit_content_sample_edit_boxes); | |
| // This declares that the IME cannot commit any content with | |
| // InputConnectionCompat#commitContent(). | |
| layout.addView(createEditTextWithContentMimeTypes(null)); | |
| // This declares that the IME can commit contents with | |
| // InputConnectionCompat#commitContent() if they match "image/gif". | |
| layout.addView(createEditTextWithContentMimeTypes(new String[]{"image/gif"})); | |
| // This declares that the IME can commit contents with | |
| // InputConnectionCompat#commitContent() if they match "image/png". | |
| layout.addView(createEditTextWithContentMimeTypes(new String[]{"image/png"})); | |
| // This declares that the IME can commit contents with | |
| // InputConnectionCompat#commitContent() if they match "image/jpeg". | |
| layout.addView(createEditTextWithContentMimeTypes(new String[]{"image/jpeg"})); | |
| // This declares that the IME can commit contents with | |
| // InputConnectionCompat#commitContent() if they match "image/webp". | |
| layout.addView(createEditTextWithContentMimeTypes(new String[]{"image/webp"})); | |
| // This declares that the IME can commit contents with | |
| // InputConnectionCompat#commitContent() if they match "image/png", "image/gif", | |
| // "image/jpeg", or "image/webp". | |
| layout.addView(createEditTextWithContentMimeTypes( | |
| new String[]{"image/png", "image/gif", "image/jpeg", "image/webp"})); | |
| mWebView = (WebView) findViewById(R.id.commit_content_webview); | |
| mMimeTypes = (TextView) findViewById(R.id.text_commit_content_mime_types); | |
| mLabel = (TextView) findViewById(R.id.text_commit_content_label); | |
| mContentUri = (TextView) findViewById(R.id.text_commit_content_content_uri); | |
| mLinkUri = (TextView) findViewById(R.id.text_commit_content_link_uri); | |
| mFlags = (TextView) findViewById(R.id.text_commit_content_link_flags); | |
| if (savedInstanceState != null) { | |
| final InputContentInfoCompat previousInputContentInfo = InputContentInfoCompat.wrap( | |
| savedInstanceState.getParcelable(INPUT_CONTENT_INFO_KEY)); | |
| final int previousFlags = savedInstanceState.getInt(COMMIT_CONTENT_FLAGS_KEY); | |
| if (previousInputContentInfo != null) { | |
| onCommitContentInternal(previousInputContentInfo, previousFlags); | |
| } | |
| } | |
| } | |
| private boolean onCommitContent(InputContentInfoCompat inputContentInfo, int flags, | |
| Bundle opts, String[] contentMimeTypes) { | |
| // Clear the temporary permission (if any). See below about why we do this here. | |
| try { | |
| if (mCurrentInputContentInfo != null) { | |
| mCurrentInputContentInfo.releasePermission(); | |
| } | |
| } catch (Exception e) { | |
| Log.e(TAG, "InputContentInfoCompat#releasePermission() failed.", e); | |
| } finally { | |
| mCurrentInputContentInfo = null; | |
| } | |
| mWebView.loadUrl("about:blank"); | |
| mMimeTypes.setText(""); | |
| mContentUri.setText(""); | |
| mLabel.setText(""); | |
| mLinkUri.setText(""); | |
| mFlags.setText(""); | |
| boolean supported = false; | |
| for (final String mimeType : contentMimeTypes) { | |
| if (inputContentInfo.getDescription().hasMimeType(mimeType)) { | |
| supported = true; | |
| break; | |
| } | |
| } | |
| if (!supported) { | |
| return false; | |
| } | |
| return onCommitContentInternal(inputContentInfo, flags); | |
| } | |
| private boolean onCommitContentInternal(InputContentInfoCompat inputContentInfo, int flags) { | |
| if ((flags & InputConnectionCompat.INPUT_CONTENT_GRANT_READ_URI_PERMISSION) != 0) { | |
| try { | |
| inputContentInfo.requestPermission(); | |
| } catch (Exception e) { | |
| Log.e(TAG, "InputContentInfoCompat#requestPermission() failed.", e); | |
| return false; | |
| } | |
| } | |
| mMimeTypes.setText( | |
| Arrays.toString(inputContentInfo.getDescription().filterMimeTypes("*/*"))); | |
| mContentUri.setText(inputContentInfo.getContentUri().toString()); | |
| mLabel.setText(inputContentInfo.getDescription().getLabel()); | |
| Uri linkUri = inputContentInfo.getLinkUri(); | |
| mLinkUri.setText(linkUri != null ? linkUri.toString() : "null"); | |
| mFlags.setText(flagsToString(flags)); | |
| mWebView.loadUrl(inputContentInfo.getContentUri().toString()); | |
| mWebView.setBackgroundColor(Color.TRANSPARENT); | |
| // Due to the asynchronous nature of WebView, it is a bit too early to call | |
| // inputContentInfo.releasePermission() here. Hence we call IC#releasePermission() when this | |
| // method is called next time. Note that calling IC#releasePermission() is just to be a | |
| // good citizen. Even if we failed to call that method, the system would eventually revoke | |
| // the permission sometime after inputContentInfo object gets garbage-collected. | |
| mCurrentInputContentInfo = inputContentInfo; | |
| mCurrentFlags = flags; | |
| return true; | |
| } | |
| @Override | |
| public void onSaveInstanceState(Bundle savedInstanceState) { | |
| if (mCurrentInputContentInfo != null) { | |
| savedInstanceState.putParcelable(INPUT_CONTENT_INFO_KEY, | |
| (Parcelable) mCurrentInputContentInfo.unwrap()); | |
| savedInstanceState.putInt(COMMIT_CONTENT_FLAGS_KEY, mCurrentFlags); | |
| } | |
| mCurrentInputContentInfo = null; | |
| mCurrentFlags = 0; | |
| super.onSaveInstanceState(savedInstanceState); | |
| } | |
| /** | |
| * Creates a new instance of {@link EditText} that is configured to specify the given content | |
| * MIME types to EditorInfo#contentMimeTypes so that developers can locally test how the current | |
| * input method behaves for such content MIME types. | |
| * | |
| * @param contentMimeTypes A {@link String} array that indicates the supported content MIME | |
| * types | |
| * @return a new instance of {@link EditText}, which specifies EditorInfo#contentMimeTypes with | |
| * the given content MIME types | |
| */ | |
| private EditText createEditTextWithContentMimeTypes(String[] contentMimeTypes) { | |
| final CharSequence hintText; | |
| final String[] mimeTypes; // our own copy of contentMimeTypes. | |
| if (contentMimeTypes == null || contentMimeTypes.length == 0) { | |
| hintText = "MIME: []"; | |
| mimeTypes = new String[0]; | |
| } else { | |
| hintText = "MIME: " + Arrays.toString(contentMimeTypes); | |
| mimeTypes = Arrays.copyOf(contentMimeTypes, contentMimeTypes.length); | |
| } | |
| EditText exitText = new EditText(this) { | |
| @Override | |
| public InputConnection onCreateInputConnection(EditorInfo editorInfo) { | |
| final InputConnection ic = super.onCreateInputConnection(editorInfo); | |
| EditorInfoCompat.setContentMimeTypes(editorInfo, mimeTypes); | |
| final InputConnectionCompat.OnCommitContentListener callback = | |
| new InputConnectionCompat.OnCommitContentListener() { | |
| @Override | |
| public boolean onCommitContent(InputContentInfoCompat inputContentInfo, | |
| int flags, Bundle opts) { | |
| return MainActivity.this.onCommitContent( | |
| inputContentInfo, flags, opts, mimeTypes); | |
| } | |
| }; | |
| return InputConnectionCompat.createWrapper(ic, editorInfo, callback); | |
| } | |
| }; | |
| exitText.setHint(hintText); | |
| exitText.setTextColor(Color.WHITE); | |
| exitText.setHintTextColor(Color.WHITE); | |
| return exitText; | |
| } | |
| /** | |
| * Converts {@code flags} specified in {@link InputConnectionCompat#commitContent( | |
| * InputConnection, EditorInfo, InputContentInfoCompat, int, Bundle)} to a human readable | |
| * string. | |
| * | |
| * @param flags the 2nd parameter of | |
| * {@link InputConnectionCompat#commitContent(InputConnection, EditorInfo, | |
| * InputContentInfoCompat, int, Bundle)} | |
| * @return a human readable string that corresponds to the given {@code flags} | |
| */ | |
| private static String flagsToString(int flags) { | |
| final ArrayList<String> tokens = new ArrayList<>(); | |
| if ((flags & InputConnectionCompat.INPUT_CONTENT_GRANT_READ_URI_PERMISSION) != 0) { | |
| tokens.add("INPUT_CONTENT_GRANT_READ_URI_PERMISSION"); | |
| flags &= ~InputConnectionCompat.INPUT_CONTENT_GRANT_READ_URI_PERMISSION; | |
| } | |
| if (flags != 0) { | |
| tokens.add("0x" + Integer.toHexString(flags)); | |
| } | |
| return TextUtils.join(" | ", tokens); | |
| } | |
| } |