diff --git a/cm/lib/main/java/org/cyanogenmod/platform/internal/PartnerInterfaceService.java b/cm/lib/main/java/org/cyanogenmod/platform/internal/PartnerInterfaceService.java index e2e248c..c0294e6 100644 --- a/cm/lib/main/java/org/cyanogenmod/platform/internal/PartnerInterfaceService.java +++ b/cm/lib/main/java/org/cyanogenmod/platform/internal/PartnerInterfaceService.java @@ -23,6 +23,7 @@ import android.content.Intent; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.media.IAudioService; +import android.net.Uri; import android.os.IBinder; import android.os.IPowerManager; @@ -46,6 +47,7 @@ import java.security.cert.X509Certificate; import java.security.interfaces.RSAPublicKey; /** @hide */ + public class PartnerInterfaceService extends SystemService { private static final String TAG = "CMSettingsService"; @@ -154,7 +156,21 @@ public class PartnerInterfaceService extends SystemService { * not allowed by the caller's permissions. */ long token = clearCallingIdentity(); - boolean success = setZenModeInternal(mode); + boolean success = setZenModeInternal(mode, -1); + restoreCallingIdentity(token); + return success; + } + + @Override + public boolean setZenModeWithDuration(int mode, long durationMillis) { + enforceModifySoundSettingsPermission(); + /* + * We need to clear the caller's identity in order to + * allow this method call to modify settings + * not allowed by the caller's permissions. + */ + long token = clearCallingIdentity(); + boolean success = setZenModeInternal(mode, durationMillis); restoreCallingIdentity(token); return success; } @@ -198,41 +214,54 @@ public class PartnerInterfaceService extends SystemService { } } - private boolean setZenModeInternal(int mode) { - ContentResolver contentResolver = mContext.getContentResolver(); + private boolean setZenModeInternal(int mode, long durationMillis) { int zenModeValue = -1; + Uri zenModeConditionUri = null; switch(mode) { case PartnerInterface.ZEN_MODE_IMPORTANT_INTERRUPTIONS: zenModeValue = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; + zenModeConditionUri = createZenModeConditionUri(durationMillis); break; case PartnerInterface.ZEN_MODE_OFF: zenModeValue = Settings.Global.ZEN_MODE_OFF; + // Leaving the condition Uri to null signifies "indefinitely" + // durationMillis is ignored break; case PartnerInterface.ZEN_MODE_NO_INTERRUPTIONS: zenModeValue = Settings.Global.ZEN_MODE_NO_INTERRUPTIONS; + zenModeConditionUri = createZenModeConditionUri(durationMillis); break; default: // Invalid mode parameter Log.w(TAG, "setZenMode() called with invalid mode: " + mode); return false; } - Settings.Global.putInt(contentResolver, - Settings.Global.ZEN_MODE, - zenModeValue); - /* + try { - // Setting the exit condition to null signifies "indefinitely" - mNotificationManager.setZenModeCondition(null); + mNotificationManager.setZenMode(zenModeValue, zenModeConditionUri, "setZenMode (PartnerInterface)"); } catch (RemoteException e) { // An error occurred, return false since the // condition failed to set. Log.e(TAG, "setZenMode() failed for mode: " + mode); return false; } - */ return true; } + private Uri createZenModeConditionUri(long durationMillis) { + // duration values that mean "indefinitely" + if (durationMillis == Long.MAX_VALUE || durationMillis < 0) { + return null; + } + final long endTimeMillis = System.currentTimeMillis() + durationMillis; + // long overflow also means "indefinitely" + if (endTimeMillis < 0) { + Log.w(TAG, "createZenModeCondition duration exceeds the max numerical limit. Defaulting to Indefinite"); + return null; + } + return android.service.notification.ZenModeConfig.toCountdownConditionId(endTimeMillis); + } + public String getHotwordPackageNameInternal() { String packageName = null; /* diff --git a/src/java/cyanogenmod/app/IPartnerInterface.aidl b/src/java/cyanogenmod/app/IPartnerInterface.aidl index b7baa4d..69ee268 100644 --- a/src/java/cyanogenmod/app/IPartnerInterface.aidl +++ b/src/java/cyanogenmod/app/IPartnerInterface.aidl @@ -23,6 +23,7 @@ interface IPartnerInterface void setAirplaneModeEnabled(boolean enabled); void setMobileDataEnabled(boolean enabled); boolean setZenMode(int mode); + boolean setZenModeWithDuration(int mode, long durationMillis); void shutdown(); void reboot(); String getCurrentHotwordPackageName(); diff --git a/src/java/cyanogenmod/app/PartnerInterface.java b/src/java/cyanogenmod/app/PartnerInterface.java index 74f230a..b06effd 100644 --- a/src/java/cyanogenmod/app/PartnerInterface.java +++ b/src/java/cyanogenmod/app/PartnerInterface.java @@ -42,17 +42,18 @@ public class PartnerInterface { * * This condition is held indefinitely until changed again. * - * @see #setZenMode + * @see #setZenMode and #setZenModeWithDuration */ public static final int ZEN_MODE_IMPORTANT_INTERRUPTIONS = 1; /** * Sets zen mode so that no interruptions will be allowed. The device is * effectively silenced indefinitely, until the mode is changed again. * - * @see #setZenMode + * @see #setZenMode and #setZenModeWithDuration */ public static final int ZEN_MODE_NO_INTERRUPTIONS = 2; + private static IPartnerInterface sService; private Context mContext; @@ -172,6 +173,36 @@ public class PartnerInterface { return false; } + /** + * Set the zen mode for the device, allow a duration parameter + * + * You will need {@link #MODIFY_SOUND_SETTINGS_PERMISSION} + * to utilize this functionality. + * + * @see #ZEN_MODE_IMPORTANT_INTERRUPTIONS + * @see #ZEN_MODE_NO_INTERRUPTIONS + * @param mode The zen mode to set the device to. + * One of {@link #ZEN_MODE_IMPORTANT_INTERRUPTIONS}, + * {@link #ZEN_MODE_NO_INTERRUPTIONS}. + * If using {@link #ZEN_MODE_OFF}, the duration will be ignored + * @param durationMillis The duration in milliseconds, + * if duration + System.currentTimeMillis() results in + * long overflow, duration will be "indefinitely". + * all durationMillis < 0 will mean "indefinitely". + * + */ + public boolean setZenModeWithDuration(int mode, long durationMillis) { + if (sService == null) { + return false; + } + try { + return sService.setZenModeWithDuration(mode, durationMillis); + } catch (RemoteException e) { + Log.e(TAG, e.getLocalizedMessage(), e); + } + return false; + } + /** * Shuts down the device, immediately. * diff --git a/tests/src/org/cyanogenmod/tests/settings/CMPartnerInterfaceTest.java b/tests/src/org/cyanogenmod/tests/settings/CMPartnerInterfaceTest.java index 4dcb2a0..72f7eec 100644 --- a/tests/src/org/cyanogenmod/tests/settings/CMPartnerInterfaceTest.java +++ b/tests/src/org/cyanogenmod/tests/settings/CMPartnerInterfaceTest.java @@ -7,6 +7,9 @@ import cyanogenmod.app.PartnerInterface; * Tests functionality added in {@link cyanogenmod.app.PartnerInterface} */ public class CMPartnerInterfaceTest extends TestActivity { + + // Zen Mode to 15 minutes + private static final long ZEN_MODE_DURATION_15_MINUTES_MS = 15 * 60000; PartnerInterface mPartnerInterface; @Override protected String tag() { @@ -55,15 +58,25 @@ public class CMPartnerInterfaceTest extends TestActivity { mPartnerInterface.setZenMode(PartnerInterface.ZEN_MODE_IMPORTANT_INTERRUPTIONS); } }, + new Test("Test set zen mode to important interruptions with 15 mins duration") { + public void run() { + mPartnerInterface.setZenModeWithDuration(PartnerInterface.ZEN_MODE_IMPORTANT_INTERRUPTIONS, ZEN_MODE_DURATION_15_MINUTES_MS); + } + }, new Test("Test set zen mode to no interruptions") { public void run() { mPartnerInterface.setZenMode(PartnerInterface.ZEN_MODE_NO_INTERRUPTIONS); } }, + new Test("Test set zen mode to no interruptions with 15 mins duration") { + public void run() { + mPartnerInterface.setZenModeWithDuration(PartnerInterface.ZEN_MODE_NO_INTERRUPTIONS, ZEN_MODE_DURATION_15_MINUTES_MS); + } + }, new Test("Test turn zen mode off") { public void run() { mPartnerInterface.setZenMode(PartnerInterface.ZEN_MODE_OFF); } }, - }; + }; }