1 /* 2 * Copyright (C) 2014 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 17 package android.service.voice; 18 19 import android.Manifest; 20 import android.annotation.NonNull; 21 import android.annotation.Nullable; 22 import android.app.AppGlobals; 23 import android.content.ComponentName; 24 import android.content.pm.PackageManager; 25 import android.content.pm.ServiceInfo; 26 import android.content.res.Resources; 27 import android.content.res.TypedArray; 28 import android.content.res.XmlResourceParser; 29 import android.os.RemoteException; 30 import android.util.AttributeSet; 31 import android.util.Log; 32 import android.util.Xml; 33 34 import org.xmlpull.v1.XmlPullParser; 35 import org.xmlpull.v1.XmlPullParserException; 36 37 import java.io.IOException; 38 39 /** @hide */ 40 public class VoiceInteractionServiceInfo { 41 static final String TAG = "VoiceInteractionServiceInfo"; 42 43 private String mParseError; 44 45 private ServiceInfo mServiceInfo; 46 private String mSessionService; 47 private String mRecognitionService; 48 private String mHotwordDetectionService; 49 private String mSettingsActivity; 50 private boolean mSupportsAssist; 51 private boolean mSupportsLaunchFromKeyguard; 52 private boolean mSupportsLocalInteraction; 53 54 /** 55 * Loads the service metadata published by the component. Success is indicated by 56 * {@link #getParseError()}. 57 * 58 * @param pm A PackageManager from which the XML can be loaded. 59 * @param comp The {@link VoiceInteractionService} component. 60 */ VoiceInteractionServiceInfo( @onNull PackageManager pm, @NonNull ComponentName comp, int userHandle)61 public VoiceInteractionServiceInfo( 62 @NonNull PackageManager pm, @NonNull ComponentName comp, int userHandle) 63 throws PackageManager.NameNotFoundException { 64 this(pm, getServiceInfoOrThrow(comp, userHandle)); 65 } 66 67 @NonNull getServiceInfoOrThrow(@onNull ComponentName comp, int userHandle)68 private static ServiceInfo getServiceInfoOrThrow(@NonNull ComponentName comp, int userHandle) 69 throws PackageManager.NameNotFoundException { 70 try { 71 ServiceInfo si = AppGlobals.getPackageManager().getServiceInfo(comp, 72 PackageManager.GET_META_DATA 73 | PackageManager.MATCH_DIRECT_BOOT_AWARE 74 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, 75 userHandle); 76 if (si != null) { 77 return si; 78 } 79 } catch (RemoteException e) { 80 } 81 throw new PackageManager.NameNotFoundException(comp.toString()); 82 } 83 84 /** 85 * Loads the service metadata published by the component. Success is indicated by 86 * {@link #getParseError()}. 87 * 88 * @param pm A PackageManager from which the XML can be loaded; usually the PackageManager 89 * from which {@code si} was originally retrieved. 90 * @param si The {@link VoiceInteractionService} info. 91 */ VoiceInteractionServiceInfo(@onNull PackageManager pm, @NonNull ServiceInfo si)92 public VoiceInteractionServiceInfo(@NonNull PackageManager pm, @NonNull ServiceInfo si) { 93 if (!Manifest.permission.BIND_VOICE_INTERACTION.equals(si.permission)) { 94 mParseError = "Service does not require permission " 95 + Manifest.permission.BIND_VOICE_INTERACTION; 96 return; 97 } 98 99 try (XmlResourceParser parser = si.loadXmlMetaData(pm, 100 VoiceInteractionService.SERVICE_META_DATA)) { 101 if (parser == null) { 102 mParseError = "No " + VoiceInteractionService.SERVICE_META_DATA 103 + " meta-data for " + si.packageName; 104 return; 105 } 106 107 Resources res = pm.getResourcesForApplication(si.applicationInfo); 108 109 AttributeSet attrs = Xml.asAttributeSet(parser); 110 111 int type; 112 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT 113 && type != XmlPullParser.START_TAG) { 114 } 115 116 String nodeName = parser.getName(); 117 if (!"voice-interaction-service".equals(nodeName)) { 118 mParseError = "Meta-data does not start with voice-interaction-service tag"; 119 return; 120 } 121 122 TypedArray array = res.obtainAttributes(attrs, 123 com.android.internal.R.styleable.VoiceInteractionService); 124 mSessionService = array.getString( 125 com.android.internal.R.styleable.VoiceInteractionService_sessionService); 126 mRecognitionService = array.getString( 127 com.android.internal.R.styleable.VoiceInteractionService_recognitionService); 128 mSettingsActivity = array.getString( 129 com.android.internal.R.styleable.VoiceInteractionService_settingsActivity); 130 mSupportsAssist = array.getBoolean( 131 com.android.internal.R.styleable.VoiceInteractionService_supportsAssist, 132 false); 133 mSupportsLaunchFromKeyguard = array.getBoolean(com.android.internal. 134 R.styleable.VoiceInteractionService_supportsLaunchVoiceAssistFromKeyguard, 135 false); 136 mSupportsLocalInteraction = array.getBoolean(com.android.internal. 137 R.styleable.VoiceInteractionService_supportsLocalInteraction, false); 138 mHotwordDetectionService = array.getString(com.android.internal.R.styleable 139 .VoiceInteractionService_hotwordDetectionService); 140 array.recycle(); 141 if (mSessionService == null) { 142 mParseError = "No sessionService specified"; 143 return; 144 } 145 if (mRecognitionService == null) { 146 mParseError = "No recognitionService specified"; 147 return; 148 } 149 } catch (XmlPullParserException | IOException | PackageManager.NameNotFoundException e) { 150 mParseError = "Error parsing voice interation service meta-data: " + e; 151 Log.w(TAG, "error parsing voice interaction service meta-data", e); 152 return; 153 } 154 mServiceInfo = si; 155 } 156 getParseError()157 public String getParseError() { 158 return mParseError; 159 } 160 getServiceInfo()161 public ServiceInfo getServiceInfo() { 162 return mServiceInfo; 163 } 164 getSessionService()165 public String getSessionService() { 166 return mSessionService; 167 } 168 getRecognitionService()169 public String getRecognitionService() { 170 return mRecognitionService; 171 } 172 getSettingsActivity()173 public String getSettingsActivity() { 174 return mSettingsActivity; 175 } 176 getSupportsAssist()177 public boolean getSupportsAssist() { 178 return mSupportsAssist; 179 } 180 getSupportsLaunchFromKeyguard()181 public boolean getSupportsLaunchFromKeyguard() { 182 return mSupportsLaunchFromKeyguard; 183 } 184 getSupportsLocalInteraction()185 public boolean getSupportsLocalInteraction() { 186 return mSupportsLocalInteraction; 187 } 188 189 @Nullable getHotwordDetectionService()190 public String getHotwordDetectionService() { 191 return mHotwordDetectionService; 192 } 193 } 194