1 /* 2 * Copyright (C) 2019 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 package android.view.textclassifier.intent; 17 18 import android.annotation.NonNull; 19 import android.annotation.Nullable; 20 import android.content.Intent; 21 import android.net.Uri; 22 import android.os.Bundle; 23 import android.text.TextUtils; 24 import android.view.textclassifier.Log; 25 import android.view.textclassifier.TextClassifier; 26 27 import com.android.internal.annotations.VisibleForTesting; 28 29 import com.google.android.textclassifier.NamedVariant; 30 import com.google.android.textclassifier.RemoteActionTemplate; 31 32 import java.util.ArrayList; 33 import java.util.List; 34 35 /** 36 * Creates intents based on {@link RemoteActionTemplate} objects. 37 * 38 * @hide 39 */ 40 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) 41 public final class TemplateIntentFactory { 42 private static final String TAG = TextClassifier.DEFAULT_LOG_TAG; 43 44 /** 45 * Constructs and returns a list of {@link LabeledIntent} based on the given templates. 46 */ 47 @Nullable create( @onNull RemoteActionTemplate[] remoteActionTemplates)48 public List<LabeledIntent> create( 49 @NonNull RemoteActionTemplate[] remoteActionTemplates) { 50 if (remoteActionTemplates.length == 0) { 51 return new ArrayList<>(); 52 } 53 final List<LabeledIntent> labeledIntents = new ArrayList<>(); 54 for (RemoteActionTemplate remoteActionTemplate : remoteActionTemplates) { 55 if (!isValidTemplate(remoteActionTemplate)) { 56 Log.w(TAG, "Invalid RemoteActionTemplate skipped."); 57 continue; 58 } 59 labeledIntents.add( 60 new LabeledIntent( 61 remoteActionTemplate.titleWithoutEntity, 62 remoteActionTemplate.titleWithEntity, 63 remoteActionTemplate.description, 64 remoteActionTemplate.descriptionWithAppName, 65 createIntent(remoteActionTemplate), 66 remoteActionTemplate.requestCode == null 67 ? LabeledIntent.DEFAULT_REQUEST_CODE 68 : remoteActionTemplate.requestCode)); 69 } 70 return labeledIntents; 71 } 72 isValidTemplate(@ullable RemoteActionTemplate remoteActionTemplate)73 private static boolean isValidTemplate(@Nullable RemoteActionTemplate remoteActionTemplate) { 74 if (remoteActionTemplate == null) { 75 Log.w(TAG, "Invalid RemoteActionTemplate: is null"); 76 return false; 77 } 78 if (TextUtils.isEmpty(remoteActionTemplate.titleWithEntity) 79 && TextUtils.isEmpty(remoteActionTemplate.titleWithoutEntity)) { 80 Log.w(TAG, "Invalid RemoteActionTemplate: title is null"); 81 return false; 82 } 83 if (TextUtils.isEmpty(remoteActionTemplate.description)) { 84 Log.w(TAG, "Invalid RemoteActionTemplate: description is null"); 85 return false; 86 } 87 if (!TextUtils.isEmpty(remoteActionTemplate.packageName)) { 88 Log.w(TAG, "Invalid RemoteActionTemplate: package name is set"); 89 return false; 90 } 91 if (TextUtils.isEmpty(remoteActionTemplate.action)) { 92 Log.w(TAG, "Invalid RemoteActionTemplate: intent action not set"); 93 return false; 94 } 95 return true; 96 } 97 createIntent(RemoteActionTemplate remoteActionTemplate)98 private static Intent createIntent(RemoteActionTemplate remoteActionTemplate) { 99 final Intent intent = new Intent(remoteActionTemplate.action); 100 final Uri uri = TextUtils.isEmpty(remoteActionTemplate.data) 101 ? null : Uri.parse(remoteActionTemplate.data).normalizeScheme(); 102 final String type = TextUtils.isEmpty(remoteActionTemplate.type) 103 ? null : Intent.normalizeMimeType(remoteActionTemplate.type); 104 intent.setDataAndType(uri, type); 105 intent.setFlags(remoteActionTemplate.flags == null ? 0 : remoteActionTemplate.flags); 106 if (remoteActionTemplate.category != null) { 107 for (String category : remoteActionTemplate.category) { 108 if (category != null) { 109 intent.addCategory(category); 110 } 111 } 112 } 113 intent.putExtras(nameVariantsToBundle(remoteActionTemplate.extras)); 114 return intent; 115 } 116 117 /** 118 * Converts an array of {@link NamedVariant} to a Bundle and returns it. 119 */ nameVariantsToBundle(@ullable NamedVariant[] namedVariants)120 public static Bundle nameVariantsToBundle(@Nullable NamedVariant[] namedVariants) { 121 if (namedVariants == null) { 122 return Bundle.EMPTY; 123 } 124 Bundle bundle = new Bundle(); 125 for (NamedVariant namedVariant : namedVariants) { 126 if (namedVariant == null) { 127 continue; 128 } 129 switch (namedVariant.getType()) { 130 case NamedVariant.TYPE_INT: 131 bundle.putInt(namedVariant.getName(), namedVariant.getInt()); 132 break; 133 case NamedVariant.TYPE_LONG: 134 bundle.putLong(namedVariant.getName(), namedVariant.getLong()); 135 break; 136 case NamedVariant.TYPE_FLOAT: 137 bundle.putFloat(namedVariant.getName(), namedVariant.getFloat()); 138 break; 139 case NamedVariant.TYPE_DOUBLE: 140 bundle.putDouble(namedVariant.getName(), namedVariant.getDouble()); 141 break; 142 case NamedVariant.TYPE_BOOL: 143 bundle.putBoolean(namedVariant.getName(), namedVariant.getBool()); 144 break; 145 case NamedVariant.TYPE_STRING: 146 bundle.putString(namedVariant.getName(), namedVariant.getString()); 147 break; 148 default: 149 Log.w(TAG, 150 "Unsupported type found in nameVariantsToBundle : " 151 + namedVariant.getType()); 152 } 153 } 154 return bundle; 155 } 156 } 157