From eabd57572113efd495df052a3694442d0915f313 Mon Sep 17 00:00:00 2001 From: Matt Garnes Date: Sat, 5 Sep 2015 14:25:07 -0700 Subject: [PATCH] Add Broadcast action and query API for AudioSource.HOTWORD. - Add ACTION_HOTWORD_INPUT_CHANGED broadcast action and related extras. - Add getCurrentHotwordPackageName() API to SettingsManager to query the current package name of the application that controls the HOTWORD input. - Rename SettingsManager to PartnerInterface. Change-Id: I5987499cd32908c47a7e8e95d644c483dc32914c --- api/cm_current.txt | 4 +- ...vice.java => PartnerInterfaceService.java} | 51 +++++++++++++---- .../cyanogenmod/app/CMContextConstants.java | 6 +- ...ngsManager.aidl => IPartnerInterface.aidl} | 3 +- ...ingsManager.java => PartnerInterface.java} | 57 ++++++++++++------- src/java/cyanogenmod/media/MediaRecorder.java | 42 +++++++++++++- src/java/cyanogenmod/os/Build.java | 2 +- system-api/cm_system-current.txt | 4 +- tests/AndroidManifest.xml | 2 +- ...rTest.java => CMPartnerInterfaceTest.java} | 28 ++++----- 10 files changed, 143 insertions(+), 56 deletions(-) rename cm/lib/main/java/org/cyanogenmod/platform/internal/{SettingsManagerService.java => PartnerInterfaceService.java} (79%) rename src/java/cyanogenmod/app/{ISettingsManager.aidl => IPartnerInterface.aidl} (92%) rename src/java/cyanogenmod/app/{SettingsManager.java => PartnerInterface.java} (76%) rename tests/src/org/cyanogenmod/tests/settings/{CMSettingsManagerTest.java => CMPartnerInterfaceTest.java} (60%) diff --git a/api/cm_current.txt b/api/cm_current.txt index 7597153..b04ab7d 100644 --- a/api/cm_current.txt +++ b/api/cm_current.txt @@ -316,8 +316,8 @@ package cyanogenmod.app { field public static final int PROFILES_STATE_ENABLED = 1; // 0x1 } - public class SettingsManager { - method public static cyanogenmod.app.SettingsManager getInstance(android.content.Context); + public class PartnerInterface { + method public static cyanogenmod.app.PartnerInterface getInstance(android.content.Context); method public void rebootDevice(); method public void setAirplaneModeEnabled(boolean); method public void setMobileDataEnabled(boolean); diff --git a/cm/lib/main/java/org/cyanogenmod/platform/internal/SettingsManagerService.java b/cm/lib/main/java/org/cyanogenmod/platform/internal/PartnerInterfaceService.java similarity index 79% rename from cm/lib/main/java/org/cyanogenmod/platform/internal/SettingsManagerService.java rename to cm/lib/main/java/org/cyanogenmod/platform/internal/PartnerInterfaceService.java index ae50755..5cad50f 100644 --- a/cm/lib/main/java/org/cyanogenmod/platform/internal/SettingsManagerService.java +++ b/cm/lib/main/java/org/cyanogenmod/platform/internal/PartnerInterfaceService.java @@ -22,6 +22,7 @@ import android.content.Context; import android.content.Intent; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; +import android.media.IAudioService; import android.os.IBinder; import android.os.IPowerManager; @@ -33,8 +34,9 @@ import android.telephony.TelephonyManager; import android.util.Log; import com.android.server.SystemService; import cyanogenmod.app.CMContextConstants; -import cyanogenmod.app.ISettingsManager; -import cyanogenmod.app.SettingsManager; +import cyanogenmod.app.IPartnerInterface; +import cyanogenmod.app.PartnerInterface; +import cyanogenmod.media.MediaRecorder; import java.io.ByteArrayInputStream; import java.security.PublicKey; @@ -44,18 +46,19 @@ import java.security.cert.X509Certificate; import java.security.interfaces.RSAPublicKey; /** {@hide} */ -public class SettingsManagerService extends SystemService { +public class PartnerInterfaceService extends SystemService { private static final String TAG = "CMSettingsService"; private Context mContext; private TelephonyManager mTelephonyManager; private INotificationManager mNotificationManager; + private IAudioService mAudioService; - public SettingsManagerService(Context context) { + public PartnerInterfaceService(Context context) { super(context); mContext = context; - publishBinderService(CMContextConstants.CM_SETTINGS_SERVICE, mService); + publishBinderService(CMContextConstants.CM_PARTNER_INTERFACE, mService); } @Override @@ -64,15 +67,17 @@ public class SettingsManagerService extends SystemService { mContext.getSystemService(Context.TELEPHONY_SERVICE); mNotificationManager = INotificationManager.Stub.asInterface( ServiceManager.getService(Context.NOTIFICATION_SERVICE)); + IBinder b = ServiceManager.getService(android.content.Context.AUDIO_SERVICE); + mAudioService = IAudioService.Stub.asInterface(b); } private void enforceModifyNetworkSettingsPermission() { - mContext.enforceCallingOrSelfPermission(SettingsManager.MODIFY_NETWORK_SETTINGS_PERMISSION, + mContext.enforceCallingOrSelfPermission(PartnerInterface.MODIFY_NETWORK_SETTINGS_PERMISSION, "You do not have permissions to change system network settings."); } private void enforceModifySoundSettingsPermission() { - mContext.enforceCallingOrSelfPermission(SettingsManager.MODIFY_SOUND_SETTINGS_PERMISSION, + mContext.enforceCallingOrSelfPermission(PartnerInterface.MODIFY_SOUND_SETTINGS_PERMISSION, "You do not have permissions to change system sound settings."); } @@ -81,7 +86,12 @@ public class SettingsManagerService extends SystemService { "You do not have permissions to shut down the device."); } - private final IBinder mService = new ISettingsManager.Stub() { + private void enforceCaptureHotwordPermission() { + mContext.enforceCallingOrSelfPermission(MediaRecorder.CAPTURE_AUDIO_HOTWORD_PERMISSION, + "You do not have permission to query the hotword input package name."); + } + + private final IBinder mService = new IPartnerInterface.Stub() { @Override public void setAirplaneModeEnabled(boolean enabled) { @@ -148,6 +158,15 @@ public class SettingsManagerService extends SystemService { restoreCallingIdentity(token); return success; } + + @Override + public String getCurrentHotwordPackageName() { + enforceCaptureHotwordPermission(); + long token = clearCallingIdentity(); + String packageName = getHotwordPackageNameInternal(); + restoreCallingIdentity(token); + return packageName; + } }; private void setAirplaneModeEnabledInternal(boolean enabled) { @@ -183,13 +202,13 @@ public class SettingsManagerService extends SystemService { ContentResolver contentResolver = mContext.getContentResolver(); int zenModeValue = -1; switch(mode) { - case SettingsManager.ZEN_MODE_IMPORTANT_INTERRUPTIONS: + case PartnerInterface.ZEN_MODE_IMPORTANT_INTERRUPTIONS: zenModeValue = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; break; - case SettingsManager.ZEN_MODE_OFF: + case PartnerInterface.ZEN_MODE_OFF: zenModeValue = Settings.Global.ZEN_MODE_OFF; break; - case SettingsManager.ZEN_MODE_NO_INTERRUPTIONS: + case PartnerInterface.ZEN_MODE_NO_INTERRUPTIONS: zenModeValue = Settings.Global.ZEN_MODE_NO_INTERRUPTIONS; break; default: @@ -211,5 +230,15 @@ public class SettingsManagerService extends SystemService { } return true; } + + public String getHotwordPackageNameInternal() { + String packageName = null; + try { + packageName = mAudioService.getCurrentHotwordInputPackageName(); + } catch (RemoteException e) { + Log.e(TAG, "getHotwordPackageName() failed."); + } + return packageName; + } } diff --git a/src/java/cyanogenmod/app/CMContextConstants.java b/src/java/cyanogenmod/app/CMContextConstants.java index b79063a..ab80b4f 100644 --- a/src/java/cyanogenmod/app/CMContextConstants.java +++ b/src/java/cyanogenmod/app/CMContextConstants.java @@ -53,14 +53,14 @@ public final class CMContextConstants { /** * Use with {@link android.content.Context#getSystemService} to retrieve a - * {@link cyanogenmod.app.SettingsManager} changing system settings. + * {@link cyanogenmod.app.PartnerInterface} interact with system settings. * * @see android.content.Context#getSystemService - * @see cyanogenmod.app.SettingsManager + * @see cyanogenmod.app.PartnerInterface * * @hide */ - public static final String CM_SETTINGS_SERVICE = "cmsettings"; + public static final String CM_PARTNER_INTERFACE = "cmpartnerinterface"; /** * Use with {@link android.content.Context#getSystemService} to retrieve a diff --git a/src/java/cyanogenmod/app/ISettingsManager.aidl b/src/java/cyanogenmod/app/IPartnerInterface.aidl similarity index 92% rename from src/java/cyanogenmod/app/ISettingsManager.aidl rename to src/java/cyanogenmod/app/IPartnerInterface.aidl index 86fa36c..b7baa4d 100644 --- a/src/java/cyanogenmod/app/ISettingsManager.aidl +++ b/src/java/cyanogenmod/app/IPartnerInterface.aidl @@ -18,11 +18,12 @@ package cyanogenmod.app; /** {@hide} */ -interface ISettingsManager +interface IPartnerInterface { void setAirplaneModeEnabled(boolean enabled); void setMobileDataEnabled(boolean enabled); boolean setZenMode(int mode); void shutdown(); void reboot(); + String getCurrentHotwordPackageName(); } diff --git a/src/java/cyanogenmod/app/SettingsManager.java b/src/java/cyanogenmod/app/PartnerInterface.java similarity index 76% rename from src/java/cyanogenmod/app/SettingsManager.java rename to src/java/cyanogenmod/app/PartnerInterface.java index b8a5802..74f230a 100644 --- a/src/java/cyanogenmod/app/SettingsManager.java +++ b/src/java/cyanogenmod/app/PartnerInterface.java @@ -24,10 +24,10 @@ import android.util.Log; /** *

- * The SettingsManager allows applications to modify a subset of system settings. + * The PartnerInterface allows applications to interact with a subset of system settings. *

*/ -public class SettingsManager { +public class PartnerInterface { /** * Turn off zen mode. This restores the original ring and interruption * settings that the user had set before zen mode was enabled. @@ -53,7 +53,7 @@ public class SettingsManager { */ public static final int ZEN_MODE_NO_INTERRUPTIONS = 2; - private static ISettingsManager sService; + private static IPartnerInterface sService; private Context mContext; @@ -70,11 +70,11 @@ public class SettingsManager { public static final String MODIFY_SOUND_SETTINGS_PERMISSION = "cyanogenmod.permission.MODIFY_SOUND_SETTINGS"; - private static final String TAG = "SettingsManager"; + private static final String TAG = "PartnerInterface"; - private static SettingsManager sSettingsManagerInstance; + private static PartnerInterface sPartnerInterfaceInstance; - private SettingsManager(Context context) { + private PartnerInterface(Context context) { Context appContext = context.getApplicationContext(); if (appContext != null) { mContext = appContext; @@ -85,25 +85,25 @@ public class SettingsManager { } /** - * Get or create an instance of the {@link cyanogenmod.app.SettingsManager} + * Get or create an instance of the {@link cyanogenmod.app.PartnerInterface} * @param context - * @return {@link SettingsManager} + * @return {@link PartnerInterface} */ - public static SettingsManager getInstance(Context context) { - if (sSettingsManagerInstance == null) { - sSettingsManagerInstance = new SettingsManager(context); + public static PartnerInterface getInstance(Context context) { + if (sPartnerInterfaceInstance == null) { + sPartnerInterfaceInstance = new PartnerInterface(context); } - return sSettingsManagerInstance; + return sPartnerInterfaceInstance; } /** @hide */ - static public ISettingsManager getService() { + static public IPartnerInterface getService() { if (sService != null) { return sService; } - IBinder b = ServiceManager.getService(CMContextConstants.CM_SETTINGS_SERVICE); + IBinder b = ServiceManager.getService(CMContextConstants.CM_PARTNER_INTERFACE); if (b != null) { - sService = ISettingsManager.Stub.asInterface(b); + sService = IPartnerInterface.Stub.asInterface(b); return sService; } else { return null; @@ -122,7 +122,7 @@ public class SettingsManager { return; } try { - getService().setAirplaneModeEnabled(enabled); + sService.setAirplaneModeEnabled(enabled); } catch (RemoteException e) { Log.e(TAG, e.getLocalizedMessage(), e); } @@ -140,7 +140,7 @@ public class SettingsManager { return; } try { - getService().setMobileDataEnabled(enabled); + sService.setMobileDataEnabled(enabled); } catch (RemoteException e) { Log.e(TAG, e.getLocalizedMessage(), e); } @@ -165,7 +165,7 @@ public class SettingsManager { return false; } try { - return getService().setZenMode(mode); + return sService.setZenMode(mode); } catch (RemoteException e) { Log.e(TAG, e.getLocalizedMessage(), e); } @@ -183,7 +183,7 @@ public class SettingsManager { return; } try { - getService().shutdown(); + sService.shutdown(); } catch (RemoteException e) { Log.e(TAG, e.getLocalizedMessage(), e); } @@ -200,9 +200,26 @@ public class SettingsManager { return; } try { - getService().reboot(); + sService.reboot(); } catch (RemoteException e) { Log.e(TAG, e.getLocalizedMessage(), e); } } + + /** + * Retrieves the package name of the application that currently holds the + * {@link cyanogenmod.media.MediaRecorder.AudioSource#HOTWORD} input. + * @return The package name or null if no application currently holds the HOTWORD input. + */ + public String getCurrentHotwordPackageName() { + if (sService == null) { + return null; + } + try { + return sService.getCurrentHotwordPackageName(); + } catch (RemoteException e) { + Log.e(TAG, e.getLocalizedMessage(), e); + } + return null; + } } diff --git a/src/java/cyanogenmod/media/MediaRecorder.java b/src/java/cyanogenmod/media/MediaRecorder.java index 7d56e36..c28cc93 100644 --- a/src/java/cyanogenmod/media/MediaRecorder.java +++ b/src/java/cyanogenmod/media/MediaRecorder.java @@ -26,7 +26,47 @@ public class MediaRecorder { public static final String CAPTURE_AUDIO_HOTWORD_PERMISSION = "android.permission.CAPTURE_AUDIO_HOTWORD"; - public class AudioSource { + /** + *

Broadcast Action: The state of the HOTWORD audio input has changed.:

+ * + * + *

This is a protected intent that can only be sent + * by the system. It can only be received by packages that hold + * {@link android.Manifest.permission#CAPTURE_AUDIO_HOTWORD}. + */ + //@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String ACTION_HOTWORD_INPUT_CHANGED + = "com.cyanogenmod.intent.action.HOTWORD_INPUT_CHANGED"; + + /** + * Extra for {@link #ACTION_HOTWORD_INPUT_CHANGED} that provides the package name of the + * app in that controlled the HOTWORD input when the state changed. Can be reused for other + * purposes. + */ + public static final String EXTRA_CURRENT_PACKAGE_NAME = + "com.cyanogenmod.intent.extra.CURRENT_PACKAGE_NAME"; + + /** + * Extra for {@link #ACTION_HOTWORD_INPUT_CHANGED} that provides the state of + * the input when the broadcast action was sent. + * @hide + */ + public static final String EXTRA_HOTWORD_INPUT_STATE = + "com.cyanogenmod.intent.extra.HOTWORD_INPUT_STATE"; + + + public static class AudioSource { /** * Audio source for preemptible, low-priority software hotword detection * It presents the same gain and pre processing tuning as diff --git a/src/java/cyanogenmod/os/Build.java b/src/java/cyanogenmod/os/Build.java index 015168b..2218447 100644 --- a/src/java/cyanogenmod/os/Build.java +++ b/src/java/cyanogenmod/os/Build.java @@ -99,7 +99,7 @@ public class Build { *

  • Hardware Abstraction Framework Access via * {@link cyanogenmod.hardware.CMHardwareManager} (Not for use by 3rd parties) *
  • MSIM API via {@link cyanogenmod.app.CMTelephonyManager} - *
  • Settings interface for partners via {@link cyanogenmod.app.SettingsManager} + *
  • Interface for partners via {@link cyanogenmod.app.PartnerInterface} *
  • Introductory Settings Provider {@link cyanogenmod.providers.CMSettings} *
  • AlarmClock API via {@link cyanogenmod.alarmclock.CyanogenModAlarmClock} * diff --git a/system-api/cm_system-current.txt b/system-api/cm_system-current.txt index 7597153..b04ab7d 100644 --- a/system-api/cm_system-current.txt +++ b/system-api/cm_system-current.txt @@ -316,8 +316,8 @@ package cyanogenmod.app { field public static final int PROFILES_STATE_ENABLED = 1; // 0x1 } - public class SettingsManager { - method public static cyanogenmod.app.SettingsManager getInstance(android.content.Context); + public class PartnerInterface { + method public static cyanogenmod.app.PartnerInterface getInstance(android.content.Context); method public void rebootDevice(); method public void setAirplaneModeEnabled(boolean); method public void setMobileDataEnabled(boolean); diff --git a/tests/AndroidManifest.xml b/tests/AndroidManifest.xml index 1e0b12a..78319f0 100644 --- a/tests/AndroidManifest.xml +++ b/tests/AndroidManifest.xml @@ -28,7 +28,7 @@ - diff --git a/tests/src/org/cyanogenmod/tests/settings/CMSettingsManagerTest.java b/tests/src/org/cyanogenmod/tests/settings/CMPartnerInterfaceTest.java similarity index 60% rename from tests/src/org/cyanogenmod/tests/settings/CMSettingsManagerTest.java rename to tests/src/org/cyanogenmod/tests/settings/CMPartnerInterfaceTest.java index f0bd97f..4dcb2a0 100644 --- a/tests/src/org/cyanogenmod/tests/settings/CMSettingsManagerTest.java +++ b/tests/src/org/cyanogenmod/tests/settings/CMPartnerInterfaceTest.java @@ -1,13 +1,13 @@ package org.cyanogenmod.tests.settings; import org.cyanogenmod.tests.TestActivity; -import cyanogenmod.app.SettingsManager; +import cyanogenmod.app.PartnerInterface; /** - * Tests functionality added in {@link cyanogenmod.app.SettingsManager} + * Tests functionality added in {@link cyanogenmod.app.PartnerInterface} */ -public class CMSettingsManagerTest extends TestActivity { - SettingsManager mSettingsManager; +public class CMPartnerInterfaceTest extends TestActivity { + PartnerInterface mPartnerInterface; @Override protected String tag() { return null; @@ -15,54 +15,54 @@ public class CMSettingsManagerTest extends TestActivity { @Override protected Test[] tests() { - mSettingsManager = SettingsManager.getInstance(this); + mPartnerInterface = PartnerInterface.getInstance(this); return mTests; } private Test[] mTests = new Test[] { new Test("Test set airplane mode to on") { public void run() { - mSettingsManager.setAirplaneModeEnabled(true); + mPartnerInterface.setAirplaneModeEnabled(true); } }, new Test("Test set airplane mode to off") { public void run() { - mSettingsManager.setAirplaneModeEnabled(false); + mPartnerInterface.setAirplaneModeEnabled(false); } }, new Test("Test set mobile data to on") { public void run() { - mSettingsManager.setMobileDataEnabled(true); + mPartnerInterface.setMobileDataEnabled(true); } }, new Test("Test set mobile data to off") { public void run() { - mSettingsManager.setMobileDataEnabled(false); + mPartnerInterface.setMobileDataEnabled(false); } }, new Test("Test reboot the device") { public void run() { - mSettingsManager.rebootDevice(); + mPartnerInterface.rebootDevice(); } }, new Test("Test shutdown the device") { public void run() { - mSettingsManager.shutdownDevice(); + mPartnerInterface.shutdownDevice(); } }, new Test("Test set zen mode to important interruptions") { public void run() { - mSettingsManager.setZenMode(SettingsManager.ZEN_MODE_IMPORTANT_INTERRUPTIONS); + mPartnerInterface.setZenMode(PartnerInterface.ZEN_MODE_IMPORTANT_INTERRUPTIONS); } }, new Test("Test set zen mode to no interruptions") { public void run() { - mSettingsManager.setZenMode(SettingsManager.ZEN_MODE_NO_INTERRUPTIONS); + mPartnerInterface.setZenMode(PartnerInterface.ZEN_MODE_NO_INTERRUPTIONS); } }, new Test("Test turn zen mode off") { public void run() { - mSettingsManager.setZenMode(SettingsManager.ZEN_MODE_OFF); + mPartnerInterface.setZenMode(PartnerInterface.ZEN_MODE_OFF); } }, };