Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 81e6b54a authored by Mao Jinlong's avatar Mao Jinlong Committed by Steve Kondik
Browse files

DeskClock: add support for power off alarm

When it is alarm boot, it will trigger power off alarm alert view at
the very beginning of the phone boot phase.
During power off alarm alert view:
  - keyguard is dismissed, will restore later
  - user can choose to continue power on the device or not

Change-Id: Id5bce67793cef694712b0591be68ef6882be6693
parent 78cc0462
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -15,6 +15,9 @@ endif
LOCAL_MODULE_TAGS := optional

LOCAL_PACKAGE_NAME := DeskClock

LOCAL_CERTIFICATE := platform

LOCAL_OVERRIDES_PACKAGES := AlarmClock

LOCAL_SRC_FILES := $(call all-java-files-under, src)
+8 −2
Original line number Diff line number Diff line
@@ -35,7 +35,7 @@
    <!-- READ_EXTERNAL_STORAGE is required to play custom ringtones from the SD card prior to M -->
    <!-- It is also required to display user-friendly names for custom ringtones in the UI. -->
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

    <uses-permission android:name="android.permission.SHUTDOWN" />
    <application android:label="@string/app_label"
                 android:name=".DeskClockApplication"
                 android:allowBackup="true"
@@ -105,7 +105,13 @@
                android:excludeFromRecents="true"
                android:theme="@style/AlarmAlertFullScreenTheme"
                android:windowSoftInputMode="stateAlwaysHidden"
                android:showOnLockScreen="true" />
                android:showOnLockScreen="true"
                >
            <intent-filter>
                <action android:name="org.codeaurora.alarm.action.POWER_OFF_ALARM" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </activity>

        <activity android:name="ScreensaverActivity"
                android:excludeFromRecents="true"
+3 −0
Original line number Diff line number Diff line
@@ -400,4 +400,7 @@
    <string name="pick_alarm_to_dismiss" msgid="5408769235866082896">"请选择要关闭的闹钟"</string>
    <string name="no_firing_alarms" msgid="4986161963178722289">"目前没有正在响铃的闹钟"</string>
    <string name="alarm_is_snoozed" msgid="7044644119744928846">"<xliff:g id="ALARM_TIME">%s</xliff:g> 的闹钟已延后 10 分钟"</string>
    <string name="power_on_text">"开机"</string>
    <string name="power_on_yes_text">"是"</string>
    <string name="power_on_no_text">"否"</string>
</resources>
+3 −0
Original line number Diff line number Diff line
@@ -1135,5 +1135,8 @@
    -->
    <string name="alarm_is_snoozed"><xliff:g id="alarm_time" example="14:20">%s</xliff:g> alarm snoozed for 10 minutes</string>

    <string name="power_on_text">Power on</string>
    <string name="power_on_yes_text">Yes</string>
    <string name="power_on_no_text">No</string>
</resources>
+182 −22
Original line number Diff line number Diff line
@@ -23,9 +23,11 @@ import android.animation.PropertyValuesHolder;
import android.animation.TimeInterpolator;
import android.animation.ValueAnimator;
import android.annotation.TargetApi;
import android.app.AlertDialog;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
@@ -33,11 +35,15 @@ import android.content.pm.ActivityInfo;
import android.graphics.Color;
import android.graphics.Rect;
import android.graphics.drawable.ColorDrawable;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.RemoteException;
import android.preference.PreferenceManager;
import android.provider.Settings;
import android.support.annotation.NonNull;
import android.support.v4.graphics.ColorUtils;
import android.support.v4.view.animation.PathInterpolatorCompat;
@@ -66,6 +72,13 @@ public class AlarmActivity extends AppCompatActivity

    private static final String LOGTAG = AlarmActivity.class.getSimpleName();

    private static final String POWER_OFF_ALARM = "powerOffAlarm";

    private static final String POWER_OFF_ALARM_MODE = "power_off_alarm_mode";

    private static final String ACTION_POWER_OFF_ALARM =
            "org.codeaurora.alarm.action.POWER_OFF_ALARM";

    private static final TimeInterpolator PULSE_INTERPOLATOR =
            PathInterpolatorCompat.create(0.4f, 0.0f, 0.2f, 1.0f);
    private static final TimeInterpolator REVEAL_INTERPOLATOR =
@@ -80,6 +93,35 @@ public class AlarmActivity extends AppCompatActivity
    private static final float BUTTON_SCALE_DEFAULT = 0.7f;
    private static final int BUTTON_DRAWABLE_ALPHA_DEFAULT = 165;

    public static boolean mIsPowerOffAlarm = false;

    private static final int SHUTDOWN_ALARM_VIEW = 1;
    private static final int SHUTDOWN_POWER_OFF = 2;

    private Context mContext;

    private boolean mIsSoonze = false;
    private boolean mIsPowerOffing = false;

    private Handler mBootHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch(msg.what) {
                case SHUTDOWN_ALARM_VIEW:
                    LogUtils.v(LOGTAG, "SHUTDOWN_ALARM_VIEW finish before sleep 500ms");
                    finish();
                    break;

                case SHUTDOWN_POWER_OFF:
                    LogUtils.v(LOGTAG, "SHUTDOWN_POWER_OFF directly power off");
                    powerOff();
                    break;

                default:// normally will not go here
            }
        }
    };

    private final Handler mHandler = new Handler();
    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
        @Override
@@ -96,7 +138,9 @@ public class AlarmActivity extends AppCompatActivity
                        dismiss();
                        break;
                    case AlarmService.ALARM_DONE_ACTION:
                        if (!mIsPowerOffAlarm || mIsSoonze) {
                            finish();
                        }
                        break;
                    default:
                        LogUtils.i(LOGTAG, "Unknown broadcast: %s", action);
@@ -149,14 +193,31 @@ public class AlarmActivity extends AppCompatActivity
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        final long instanceId = AlarmInstance.getId(getIntent().getData());
        mAlarmInstance = AlarmInstance.getInstance(getContentResolver(), instanceId);
        Uri intentData = getIntent().getData();
        String intentAction = getIntent().getAction();

        if (intentAction == ACTION_POWER_OFF_ALARM) {
            mIsPowerOffAlarm = true;
        }

        mContext = getApplicationContext();

        if (mIsPowerOffAlarm) {
            mAlarmInstance = AlarmInstance.getFirstAlarmInstance(mContext.getContentResolver());

            Settings.System.putInt(mContext.getContentResolver(), POWER_OFF_ALARM_MODE, 1);

        } else if (intentData != null) {
            long instanceId = AlarmInstance.getId(intentData);
            mAlarmInstance = AlarmInstance.getInstance(this.getContentResolver(), instanceId);
        }

        if (mAlarmInstance == null) {
            // The alarm was deleted before the activity got created, so just finish()
            LogUtils.e(LOGTAG, "Error displaying alarm for intent: %s", getIntent());
            finish();
            return;
        } else if (mAlarmInstance.mAlarmState != AlarmInstance.FIRED_STATE) {
        } else if (!mIsPowerOffAlarm && mAlarmInstance.mAlarmState != AlarmInstance.FIRED_STATE) {
            LogUtils.i(LOGTAG, "Skip displaying alarm for instance: %s", mAlarmInstance);
            finish();
            return;
@@ -169,11 +230,21 @@ public class AlarmActivity extends AppCompatActivity
                .getString(SettingsActivity.KEY_VOLUME_BEHAVIOR,
                        SettingsActivity.DEFAULT_VOLUME_BEHAVIOR);

        if (mIsPowerOffAlarm) {
            getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY);
            getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
                    | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD
                    | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
                    | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
                    | WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON
                    | WindowManager.LayoutParams.FLAG_FULLSCREEN);
        } else {
            getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
                    | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD
                    | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
                    | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
                    | WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON);
        }

        // Hide navigation bar to minimize accidental tap on Home key
        hideNavigationBar();
@@ -231,6 +302,10 @@ public class AlarmActivity extends AppCompatActivity
        mPulseAnimator.setInterpolator(PULSE_INTERPOLATOR);
        mPulseAnimator.setRepeatCount(ValueAnimator.INFINITE);
        mPulseAnimator.start();

        if (mAlarmInstance != null && mIsPowerOffAlarm) {
            AlarmStateManager.setFiredState(getApplicationContext(), mAlarmInstance);
        }
    }

    @Override
@@ -246,6 +321,14 @@ public class AlarmActivity extends AppCompatActivity
    protected void onResume() {
        super.onResume();

        Uri intentData = getIntent().getData();

        String intentAction = getIntent().getAction();
        if (intentAction == ACTION_POWER_OFF_ALARM) {
            mIsPowerOffAlarm = true;
        }

        if(!mIsPowerOffAlarm && intentData != null) {
            // Re-query for AlarmInstance in case the state has changed externally
            final long instanceId = AlarmInstance.getId(getIntent().getData());
            mAlarmInstance = AlarmInstance.getInstance(getContentResolver(), instanceId);
@@ -257,11 +340,12 @@ public class AlarmActivity extends AppCompatActivity
            }

            // Verify that the alarm is still firing before showing the activity
        if (mAlarmInstance.mAlarmState != AlarmInstance.FIRED_STATE) {
            if (!mIsPowerOffAlarm && mAlarmInstance.mAlarmState != AlarmInstance.FIRED_STATE) {
                LogUtils.i(LOGTAG, "Skip displaying alarm for instance: %s", mAlarmInstance);
                finish();
                return;
            }
        }

        if (!mReceiverRegistered) {
            // Register to get the alarm done/snooze/dismiss intent.
@@ -286,6 +370,24 @@ public class AlarmActivity extends AppCompatActivity
            unregisterReceiver(mReceiver);
            mReceiverRegistered = false;
        }

    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (mIsPowerOffAlarm) {
            // Boot alarm should not be destroyed before being handled.
            if (!mIsPowerOffing) {
                if (!mAlarmHandled) {
                    Settings.System.putInt(mContext.getContentResolver(), POWER_OFF_ALARM_MODE, 0);
                    mIsPowerOffAlarm = false;
                    LogUtils.d(LOGTAG, "onDestroy setSnoozeState = " + mAlarmInstance);
                    AlarmStateManager.setSnoozeState(this, mAlarmInstance, false );
                }
            }
        }

    }

    @Override
@@ -459,6 +561,8 @@ public class AlarmActivity extends AppCompatActivity
     * Perform snooze animation and send snooze intent.
     */
    private void snooze() {
        mIsSoonze = true;

        mAlarmHandled = true;
        LogUtils.v(LOGTAG, "Snoozed: %s", mAlarmInstance);

@@ -501,6 +605,10 @@ public class AlarmActivity extends AppCompatActivity

        // Unbind here, otherwise alarm will keep ringing until activity finishes.
        unbindAlarmService();

        if (mIsPowerOffAlarm) {
            showPowerOffDialog();
        }
    }

    /**
@@ -616,12 +724,64 @@ public class AlarmActivity extends AppCompatActivity
                mHandler.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        if ((!mIsPowerOffAlarm && !mIsPowerOffing) || mIsSoonze) {
                            finish();
                        }
                    }
                }, ALERT_DISMISS_DELAY_MILLIS);
            }
        });

        return alertAnimator;
    }

    /**
     * Implement power off function immediately.
     */
    private void powerOff() {
        Intent requestShutdown = new Intent(Intent.ACTION_REQUEST_SHUTDOWN);
        requestShutdown.putExtra(Intent.EXTRA_KEY_CONFIRM, false);
        requestShutdown.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        mContext.startActivity(requestShutdown);
    }

    private void showPowerOffDialog() {
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setMessage(R.string.power_on_text)
               .setTitle(R.string.alarm_list_title);
        builder.setPositiveButton(R.string.power_on_yes_text,
                new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        Settings.System.putInt(mContext.getContentResolver(),
                                POWER_OFF_ALARM_MODE, 0);
                        mIsPowerOffAlarm = false;
                        mBootHandler.sendEmptyMessage(SHUTDOWN_ALARM_VIEW);
                    }
                });
        builder.setNegativeButton(R.string.power_on_no_text,
                new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        Settings.System.putInt(mContext.getContentResolver(),
                                POWER_OFF_ALARM_MODE, 0);
                        mIsPowerOffAlarm = false;
                        mIsPowerOffing = true;
                        mBootHandler.sendEmptyMessage(SHUTDOWN_POWER_OFF);
                    }
                });

        AlertDialog poweroffDialog = builder.create();
        poweroffDialog.setCancelable(false);
        poweroffDialog.setCanceledOnTouchOutside(false);
        poweroffDialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED |
                WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD |
                WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON |
                WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON |
                WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON |
                WindowManager.LayoutParams.FLAG_FULLSCREEN |
                WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN);
        poweroffDialog.show();
    }

}
Loading