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
This commit is contained in:
Matt Garnes 2015-09-05 14:25:07 -07:00 committed by Raj Yengisetty
parent a458122384
commit eabd575721
10 changed files with 143 additions and 56 deletions

View File

@ -316,8 +316,8 @@ package cyanogenmod.app {
field public static final int PROFILES_STATE_ENABLED = 1; // 0x1 field public static final int PROFILES_STATE_ENABLED = 1; // 0x1
} }
public class SettingsManager { public class PartnerInterface {
method public static cyanogenmod.app.SettingsManager getInstance(android.content.Context); method public static cyanogenmod.app.PartnerInterface getInstance(android.content.Context);
method public void rebootDevice(); method public void rebootDevice();
method public void setAirplaneModeEnabled(boolean); method public void setAirplaneModeEnabled(boolean);
method public void setMobileDataEnabled(boolean); method public void setMobileDataEnabled(boolean);

View File

@ -22,6 +22,7 @@ import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.pm.PackageInfo; import android.content.pm.PackageInfo;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.media.IAudioService;
import android.os.IBinder; import android.os.IBinder;
import android.os.IPowerManager; import android.os.IPowerManager;
@ -33,8 +34,9 @@ import android.telephony.TelephonyManager;
import android.util.Log; import android.util.Log;
import com.android.server.SystemService; import com.android.server.SystemService;
import cyanogenmod.app.CMContextConstants; import cyanogenmod.app.CMContextConstants;
import cyanogenmod.app.ISettingsManager; import cyanogenmod.app.IPartnerInterface;
import cyanogenmod.app.SettingsManager; import cyanogenmod.app.PartnerInterface;
import cyanogenmod.media.MediaRecorder;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.security.PublicKey; import java.security.PublicKey;
@ -44,18 +46,19 @@ import java.security.cert.X509Certificate;
import java.security.interfaces.RSAPublicKey; import java.security.interfaces.RSAPublicKey;
/** {@hide} */ /** {@hide} */
public class SettingsManagerService extends SystemService { public class PartnerInterfaceService extends SystemService {
private static final String TAG = "CMSettingsService"; private static final String TAG = "CMSettingsService";
private Context mContext; private Context mContext;
private TelephonyManager mTelephonyManager; private TelephonyManager mTelephonyManager;
private INotificationManager mNotificationManager; private INotificationManager mNotificationManager;
private IAudioService mAudioService;
public SettingsManagerService(Context context) { public PartnerInterfaceService(Context context) {
super(context); super(context);
mContext = context; mContext = context;
publishBinderService(CMContextConstants.CM_SETTINGS_SERVICE, mService); publishBinderService(CMContextConstants.CM_PARTNER_INTERFACE, mService);
} }
@Override @Override
@ -64,15 +67,17 @@ public class SettingsManagerService extends SystemService {
mContext.getSystemService(Context.TELEPHONY_SERVICE); mContext.getSystemService(Context.TELEPHONY_SERVICE);
mNotificationManager = INotificationManager.Stub.asInterface( mNotificationManager = INotificationManager.Stub.asInterface(
ServiceManager.getService(Context.NOTIFICATION_SERVICE)); ServiceManager.getService(Context.NOTIFICATION_SERVICE));
IBinder b = ServiceManager.getService(android.content.Context.AUDIO_SERVICE);
mAudioService = IAudioService.Stub.asInterface(b);
} }
private void enforceModifyNetworkSettingsPermission() { 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."); "You do not have permissions to change system network settings.");
} }
private void enforceModifySoundSettingsPermission() { 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."); "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."); "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 @Override
public void setAirplaneModeEnabled(boolean enabled) { public void setAirplaneModeEnabled(boolean enabled) {
@ -148,6 +158,15 @@ public class SettingsManagerService extends SystemService {
restoreCallingIdentity(token); restoreCallingIdentity(token);
return success; return success;
} }
@Override
public String getCurrentHotwordPackageName() {
enforceCaptureHotwordPermission();
long token = clearCallingIdentity();
String packageName = getHotwordPackageNameInternal();
restoreCallingIdentity(token);
return packageName;
}
}; };
private void setAirplaneModeEnabledInternal(boolean enabled) { private void setAirplaneModeEnabledInternal(boolean enabled) {
@ -183,13 +202,13 @@ public class SettingsManagerService extends SystemService {
ContentResolver contentResolver = mContext.getContentResolver(); ContentResolver contentResolver = mContext.getContentResolver();
int zenModeValue = -1; int zenModeValue = -1;
switch(mode) { switch(mode) {
case SettingsManager.ZEN_MODE_IMPORTANT_INTERRUPTIONS: case PartnerInterface.ZEN_MODE_IMPORTANT_INTERRUPTIONS:
zenModeValue = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; zenModeValue = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
break; break;
case SettingsManager.ZEN_MODE_OFF: case PartnerInterface.ZEN_MODE_OFF:
zenModeValue = Settings.Global.ZEN_MODE_OFF; zenModeValue = Settings.Global.ZEN_MODE_OFF;
break; break;
case SettingsManager.ZEN_MODE_NO_INTERRUPTIONS: case PartnerInterface.ZEN_MODE_NO_INTERRUPTIONS:
zenModeValue = Settings.Global.ZEN_MODE_NO_INTERRUPTIONS; zenModeValue = Settings.Global.ZEN_MODE_NO_INTERRUPTIONS;
break; break;
default: default:
@ -211,5 +230,15 @@ public class SettingsManagerService extends SystemService {
} }
return true; return true;
} }
public String getHotwordPackageNameInternal() {
String packageName = null;
try {
packageName = mAudioService.getCurrentHotwordInputPackageName();
} catch (RemoteException e) {
Log.e(TAG, "getHotwordPackageName() failed.");
}
return packageName;
}
} }

View File

@ -53,14 +53,14 @@ public final class CMContextConstants {
/** /**
* Use with {@link android.content.Context#getSystemService} to retrieve a * 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 android.content.Context#getSystemService
* @see cyanogenmod.app.SettingsManager * @see cyanogenmod.app.PartnerInterface
* *
* @hide * @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 * Use with {@link android.content.Context#getSystemService} to retrieve a

View File

@ -18,11 +18,12 @@
package cyanogenmod.app; package cyanogenmod.app;
/** {@hide} */ /** {@hide} */
interface ISettingsManager interface IPartnerInterface
{ {
void setAirplaneModeEnabled(boolean enabled); void setAirplaneModeEnabled(boolean enabled);
void setMobileDataEnabled(boolean enabled); void setMobileDataEnabled(boolean enabled);
boolean setZenMode(int mode); boolean setZenMode(int mode);
void shutdown(); void shutdown();
void reboot(); void reboot();
String getCurrentHotwordPackageName();
} }

View File

@ -24,10 +24,10 @@ import android.util.Log;
/** /**
* <p> * <p>
* The SettingsManager allows applications to modify a subset of system settings. * The PartnerInterface allows applications to interact with a subset of system settings.
* </p> * </p>
*/ */
public class SettingsManager { public class PartnerInterface {
/** /**
* Turn off zen mode. This restores the original ring and interruption * Turn off zen mode. This restores the original ring and interruption
* settings that the user had set before zen mode was enabled. * 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; public static final int ZEN_MODE_NO_INTERRUPTIONS = 2;
private static ISettingsManager sService; private static IPartnerInterface sService;
private Context mContext; private Context mContext;
@ -70,11 +70,11 @@ public class SettingsManager {
public static final String MODIFY_SOUND_SETTINGS_PERMISSION = public static final String MODIFY_SOUND_SETTINGS_PERMISSION =
"cyanogenmod.permission.MODIFY_SOUND_SETTINGS"; "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(); Context appContext = context.getApplicationContext();
if (appContext != null) { if (appContext != null) {
mContext = appContext; 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 * @param context
* @return {@link SettingsManager} * @return {@link PartnerInterface}
*/ */
public static SettingsManager getInstance(Context context) { public static PartnerInterface getInstance(Context context) {
if (sSettingsManagerInstance == null) { if (sPartnerInterfaceInstance == null) {
sSettingsManagerInstance = new SettingsManager(context); sPartnerInterfaceInstance = new PartnerInterface(context);
} }
return sSettingsManagerInstance; return sPartnerInterfaceInstance;
} }
/** @hide */ /** @hide */
static public ISettingsManager getService() { static public IPartnerInterface getService() {
if (sService != null) { if (sService != null) {
return sService; return sService;
} }
IBinder b = ServiceManager.getService(CMContextConstants.CM_SETTINGS_SERVICE); IBinder b = ServiceManager.getService(CMContextConstants.CM_PARTNER_INTERFACE);
if (b != null) { if (b != null) {
sService = ISettingsManager.Stub.asInterface(b); sService = IPartnerInterface.Stub.asInterface(b);
return sService; return sService;
} else { } else {
return null; return null;
@ -122,7 +122,7 @@ public class SettingsManager {
return; return;
} }
try { try {
getService().setAirplaneModeEnabled(enabled); sService.setAirplaneModeEnabled(enabled);
} catch (RemoteException e) { } catch (RemoteException e) {
Log.e(TAG, e.getLocalizedMessage(), e); Log.e(TAG, e.getLocalizedMessage(), e);
} }
@ -140,7 +140,7 @@ public class SettingsManager {
return; return;
} }
try { try {
getService().setMobileDataEnabled(enabled); sService.setMobileDataEnabled(enabled);
} catch (RemoteException e) { } catch (RemoteException e) {
Log.e(TAG, e.getLocalizedMessage(), e); Log.e(TAG, e.getLocalizedMessage(), e);
} }
@ -165,7 +165,7 @@ public class SettingsManager {
return false; return false;
} }
try { try {
return getService().setZenMode(mode); return sService.setZenMode(mode);
} catch (RemoteException e) { } catch (RemoteException e) {
Log.e(TAG, e.getLocalizedMessage(), e); Log.e(TAG, e.getLocalizedMessage(), e);
} }
@ -183,7 +183,7 @@ public class SettingsManager {
return; return;
} }
try { try {
getService().shutdown(); sService.shutdown();
} catch (RemoteException e) { } catch (RemoteException e) {
Log.e(TAG, e.getLocalizedMessage(), e); Log.e(TAG, e.getLocalizedMessage(), e);
} }
@ -200,9 +200,26 @@ public class SettingsManager {
return; return;
} }
try { try {
getService().reboot(); sService.reboot();
} catch (RemoteException e) { } catch (RemoteException e) {
Log.e(TAG, e.getLocalizedMessage(), 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;
}
} }

View File

@ -26,7 +26,47 @@ public class MediaRecorder {
public static final String CAPTURE_AUDIO_HOTWORD_PERMISSION public static final String CAPTURE_AUDIO_HOTWORD_PERMISSION
= "android.permission.CAPTURE_AUDIO_HOTWORD"; = "android.permission.CAPTURE_AUDIO_HOTWORD";
public class AudioSource { /**
* <p>Broadcast Action: The state of the HOTWORD audio input has changed.:</p>
* <ul>
* <li><em>state</em> - A String value indicating the state of the input.
* {@link #EXTRA_HOTWORD_INPUT_STATE}. The value will be one of:
* {@link android.media.AudioRecord#RECORDSTATE_RECORDING} or
* {@link android.media.AudioRecord#RECORDSTATE_STOPPED}.
* </li>
* <li><em>package</em> - A String value indicating the package name of the application
* that currently holds the HOTWORD input.
* {@link #EXTRA_CURRENT_PACKAGE_NAME}
* </li>
* </ul>
*
* <p class="note">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 * Audio source for preemptible, low-priority software hotword detection
* It presents the same gain and pre processing tuning as * It presents the same gain and pre processing tuning as

View File

@ -99,7 +99,7 @@ public class Build {
* <li>Hardware Abstraction Framework Access via * <li>Hardware Abstraction Framework Access via
* {@link cyanogenmod.hardware.CMHardwareManager} (Not for use by 3rd parties) * {@link cyanogenmod.hardware.CMHardwareManager} (Not for use by 3rd parties)
* <li>MSIM API via {@link cyanogenmod.app.CMTelephonyManager} * <li>MSIM API via {@link cyanogenmod.app.CMTelephonyManager}
* <li>Settings interface for partners via {@link cyanogenmod.app.SettingsManager} * <li>Interface for partners via {@link cyanogenmod.app.PartnerInterface}
* <li>Introductory Settings Provider {@link cyanogenmod.providers.CMSettings} * <li>Introductory Settings Provider {@link cyanogenmod.providers.CMSettings}
* <li>AlarmClock API via {@link cyanogenmod.alarmclock.CyanogenModAlarmClock} * <li>AlarmClock API via {@link cyanogenmod.alarmclock.CyanogenModAlarmClock}
* </ul> * </ul>

View File

@ -316,8 +316,8 @@ package cyanogenmod.app {
field public static final int PROFILES_STATE_ENABLED = 1; // 0x1 field public static final int PROFILES_STATE_ENABLED = 1; // 0x1
} }
public class SettingsManager { public class PartnerInterface {
method public static cyanogenmod.app.SettingsManager getInstance(android.content.Context); method public static cyanogenmod.app.PartnerInterface getInstance(android.content.Context);
method public void rebootDevice(); method public void rebootDevice();
method public void setAirplaneModeEnabled(boolean); method public void setAirplaneModeEnabled(boolean);
method public void setMobileDataEnabled(boolean); method public void setMobileDataEnabled(boolean);

View File

@ -28,7 +28,7 @@
<category android:name="android.intent.category.LAUNCHER"/> <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter> </intent-filter>
</activity> </activity>
<activity android:name=".settings.CMSettingsManagerTest" <activity android:name=".settings.CMPartnerInterfaceTest"
android:label="@string/settings_tests_activity_name"> android:label="@string/settings_tests_activity_name">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN"/> <action android:name="android.intent.action.MAIN"/>

View File

@ -1,13 +1,13 @@
package org.cyanogenmod.tests.settings; package org.cyanogenmod.tests.settings;
import org.cyanogenmod.tests.TestActivity; 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 { public class CMPartnerInterfaceTest extends TestActivity {
SettingsManager mSettingsManager; PartnerInterface mPartnerInterface;
@Override @Override
protected String tag() { protected String tag() {
return null; return null;
@ -15,54 +15,54 @@ public class CMSettingsManagerTest extends TestActivity {
@Override @Override
protected Test[] tests() { protected Test[] tests() {
mSettingsManager = SettingsManager.getInstance(this); mPartnerInterface = PartnerInterface.getInstance(this);
return mTests; return mTests;
} }
private Test[] mTests = new Test[] { private Test[] mTests = new Test[] {
new Test("Test set airplane mode to on") { new Test("Test set airplane mode to on") {
public void run() { public void run() {
mSettingsManager.setAirplaneModeEnabled(true); mPartnerInterface.setAirplaneModeEnabled(true);
} }
}, },
new Test("Test set airplane mode to off") { new Test("Test set airplane mode to off") {
public void run() { public void run() {
mSettingsManager.setAirplaneModeEnabled(false); mPartnerInterface.setAirplaneModeEnabled(false);
} }
}, },
new Test("Test set mobile data to on") { new Test("Test set mobile data to on") {
public void run() { public void run() {
mSettingsManager.setMobileDataEnabled(true); mPartnerInterface.setMobileDataEnabled(true);
} }
}, },
new Test("Test set mobile data to off") { new Test("Test set mobile data to off") {
public void run() { public void run() {
mSettingsManager.setMobileDataEnabled(false); mPartnerInterface.setMobileDataEnabled(false);
} }
}, },
new Test("Test reboot the device") { new Test("Test reboot the device") {
public void run() { public void run() {
mSettingsManager.rebootDevice(); mPartnerInterface.rebootDevice();
} }
}, },
new Test("Test shutdown the device") { new Test("Test shutdown the device") {
public void run() { public void run() {
mSettingsManager.shutdownDevice(); mPartnerInterface.shutdownDevice();
} }
}, },
new Test("Test set zen mode to important interruptions") { new Test("Test set zen mode to important interruptions") {
public void run() { 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") { new Test("Test set zen mode to no interruptions") {
public void run() { public void run() {
mSettingsManager.setZenMode(SettingsManager.ZEN_MODE_NO_INTERRUPTIONS); mPartnerInterface.setZenMode(PartnerInterface.ZEN_MODE_NO_INTERRUPTIONS);
} }
}, },
new Test("Test turn zen mode off") { new Test("Test turn zen mode off") {
public void run() { public void run() {
mSettingsManager.setZenMode(SettingsManager.ZEN_MODE_OFF); mPartnerInterface.setZenMode(PartnerInterface.ZEN_MODE_OFF);
} }
}, },
}; };