Flutter Engine
The Flutter Engine
ProcessTextPlugin.java
Go to the documentation of this file.
1// Copyright 2013 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5package io.flutter.plugin.text;
6
7import static io.flutter.Build.API_LEVELS;
8
9import android.annotation.TargetApi;
10import android.app.Activity;
11import android.content.Intent;
12import android.content.pm.PackageManager;
13import android.content.pm.ResolveInfo;
14import android.os.Build;
15import androidx.annotation.NonNull;
16import androidx.annotation.Nullable;
17import androidx.annotation.RequiresApi;
18import io.flutter.embedding.engine.plugins.FlutterPlugin;
19import io.flutter.embedding.engine.plugins.activity.ActivityAware;
20import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding;
21import io.flutter.embedding.engine.systemchannels.ProcessTextChannel;
22import io.flutter.plugin.common.MethodChannel;
23import io.flutter.plugin.common.PluginRegistry.ActivityResultListener;
24import java.util.HashMap;
25import java.util.List;
26import java.util.Map;
27
29 implements FlutterPlugin,
32 ProcessTextChannel.ProcessTextMethodHandler {
33 private static final String TAG = "ProcessTextPlugin";
34
35 @NonNull private final ProcessTextChannel processTextChannel;
36 @NonNull private final PackageManager packageManager;
37 @Nullable private ActivityPluginBinding activityBinding;
38 private Map<String, ResolveInfo> resolveInfosById;
39
40 @NonNull
41 private Map<Integer, MethodChannel.Result> requestsByCode =
42 new HashMap<Integer, MethodChannel.Result>();
43
44 public ProcessTextPlugin(@NonNull ProcessTextChannel processTextChannel) {
45 this.processTextChannel = processTextChannel;
46 this.packageManager = processTextChannel.packageManager;
47
48 processTextChannel.setMethodHandler(this);
49 }
50
51 @Override
52 public Map<String, String> queryTextActions() {
53 if (resolveInfosById == null) {
54 cacheResolveInfos();
55 }
56 Map<String, String> result = new HashMap<String, String>();
57 for (String id : resolveInfosById.keySet()) {
58 final ResolveInfo info = resolveInfosById.get(id);
59 result.put(id, info.loadLabel(packageManager).toString());
60 }
61 return result;
62 }
63
64 @Override
65 public void processTextAction(
66 @NonNull String id,
67 @NonNull String text,
68 @NonNull boolean readOnly,
69 @NonNull MethodChannel.Result result) {
70 if (activityBinding == null) {
71 result.error("error", "Plugin not bound to an Activity", null);
72 return;
73 }
74
75 if (Build.VERSION.SDK_INT < API_LEVELS.API_23) {
76 result.error("error", "Android version not supported", null);
77 return;
78 }
79
80 if (resolveInfosById == null) {
81 result.error("error", "Can not process text actions before calling queryTextActions", null);
82 return;
83 }
84
85 final ResolveInfo info = resolveInfosById.get(id);
86 if (info == null) {
87 result.error("error", "Text processing activity not found", null);
88 return;
89 }
90
91 Integer requestCode = result.hashCode();
92 requestsByCode.put(requestCode, result);
93
94 Intent intent = new Intent();
95 intent.setClassName(info.activityInfo.packageName, info.activityInfo.name);
96 intent.setAction(Intent.ACTION_PROCESS_TEXT);
97 intent.setType("text/plain");
98 intent.putExtra(Intent.EXTRA_PROCESS_TEXT, text);
99 intent.putExtra(Intent.EXTRA_PROCESS_TEXT_READONLY, readOnly);
100
101 // Start the text processing activity. When the activity completes, the onActivityResult
102 // callback
103 // is called.
104 activityBinding.getActivity().startActivityForResult(intent, requestCode);
105 }
106
107 private void cacheResolveInfos() {
108 resolveInfosById = new HashMap<String, ResolveInfo>();
109
110 if (Build.VERSION.SDK_INT < API_LEVELS.API_23) {
111 return;
112 }
113
114 Intent intent = new Intent().setAction(Intent.ACTION_PROCESS_TEXT).setType("text/plain");
115
116 List<ResolveInfo> infos;
117 if (Build.VERSION.SDK_INT >= API_LEVELS.API_33) {
118 infos = packageManager.queryIntentActivities(intent, PackageManager.ResolveInfoFlags.of(0));
119 } else {
120 infos = packageManager.queryIntentActivities(intent, 0);
121 }
122
123 for (ResolveInfo info : infos) {
124 final String id = info.activityInfo.name;
125 final String label = info.loadLabel(packageManager).toString();
126 resolveInfosById.put(id, info);
127 }
128 }
129
130 /**
131 * Executed when a text processing activity terminates.
132 *
133 * <p>When an activity returns a value, the request is completed successfully and returns the
134 * processed text.
135 *
136 * <p>When an activity does not return a value. the request is completed successfully and returns
137 * null.
138 */
139 @TargetApi(API_LEVELS.API_23)
140 @RequiresApi(API_LEVELS.API_23)
141 public boolean onActivityResult(int requestCode, int resultCode, @Nullable Intent intent) {
142 // Return early if the result is not related to a request sent by this plugin.
143 if (!requestsByCode.containsKey(requestCode)) {
144 return false;
145 }
146
147 String result = null;
148 if (resultCode == Activity.RESULT_OK) {
149 result = intent.getStringExtra(Intent.EXTRA_PROCESS_TEXT);
150 }
151 requestsByCode.remove(requestCode).success(result);
152 return true;
153 }
154
155 /**
156 * Unregisters this {@code ProcessTextPlugin} as the {@code
157 * ProcessTextChannel.ProcessTextMethodHandler}, for the {@link
158 * io.flutter.embedding.engine.systemchannels.ProcessTextChannel}.
159 *
160 * <p>Do not invoke any methods on a {@code ProcessTextPlugin} after invoking this method.
161 */
162 public void destroy() {
163 processTextChannel.setMethodHandler(null);
164 }
165
166 // FlutterPlugin interface implementation.
167
168 public void onAttachedToEngine(@NonNull FlutterPluginBinding binding) {
169 // Nothing to do because this plugin is instantiated by the engine.
170 }
171
172 public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {
173 // Nothing to do because this plugin is instantiated by the engine.
174 }
175
176 // ActivityAware interface implementation.
177 //
178 // Store the binding and manage the activity result listener.
179
180 public void onAttachedToActivity(@NonNull ActivityPluginBinding binding) {
181 this.activityBinding = binding;
182 this.activityBinding.addActivityResultListener(this);
183 };
184
186 this.activityBinding.removeActivityResultListener(this);
187 this.activityBinding = null;
188 }
189
191 this.activityBinding = binding;
192 this.activityBinding.addActivityResultListener(this);
193 }
194
196 this.activityBinding.removeActivityResultListener(this);
197 this.activityBinding = null;
198 }
199}
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition: DM.cpp:213
static final int API_23
Definition: Build.java:13
void processTextAction( @NonNull String id, @NonNull String text, @NonNull boolean readOnly, @NonNull MethodChannel.Result result)
void onReattachedToActivityForConfigChanges(@NonNull ActivityPluginBinding binding)
void onAttachedToActivity(@NonNull ActivityPluginBinding binding)
boolean onActivityResult(int requestCode, int resultCode, @Nullable Intent intent)
ProcessTextPlugin(@NonNull ProcessTextChannel processTextChannel)
void onAttachedToEngine(@NonNull FlutterPluginBinding binding)
void onDetachedFromEngine(@NonNull FlutterPluginBinding binding)
GAsyncResult * result
std::u16string text
def Build(configs, env, options)
Definition: build.py:232