Screen record status bar icon
Adds a status bar icon that will show for system ui screen recordings. The icon displays a countdown and then a static recording indicator. Bug: 137153302 Test: manual Change-Id: Ie30b47c5b08bab042f92e9b29cc42a4a58b10ced
This commit is contained in:
@@ -59,6 +59,7 @@
|
||||
<item><xliff:g id="id">@string/status_bar_airplane</xliff:g></item>
|
||||
<item><xliff:g id="id">@string/status_bar_battery</xliff:g></item>
|
||||
<item><xliff:g id="id">@string/status_bar_sensors_off</xliff:g></item>
|
||||
<item><xliff:g id="id">@string/status_bar_screen_record</xliff:g></item>
|
||||
</string-array>
|
||||
|
||||
<string translatable="false" name="status_bar_rotate">rotate</string>
|
||||
@@ -94,6 +95,7 @@
|
||||
<string translatable="false" name="status_bar_camera">camera</string>
|
||||
<string translatable="false" name="status_bar_airplane">airplane</string>
|
||||
<string translatable="false" name="status_bar_sensors_off">sensors_off</string>
|
||||
<string translatable="false" name="status_bar_screen_record">screen_record</string>
|
||||
|
||||
<!-- Flag indicating whether the surface flinger has limited
|
||||
alpha compositing functionality in hardware. If set, the window
|
||||
|
||||
@@ -2908,6 +2908,7 @@
|
||||
<java-symbol type="string" name="status_bar_microphone" />
|
||||
<java-symbol type="string" name="status_bar_camera" />
|
||||
<java-symbol type="string" name="status_bar_sensors_off" />
|
||||
<java-symbol type="string" name="status_bar_screen_record" />
|
||||
|
||||
<!-- Locale picker -->
|
||||
<java-symbol type="id" name="locale_search_menu" />
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
<!--
|
||||
Copyright (C) 2020 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="?android:attr/colorError"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:pathData="M10,0L14,0A10,10 0,0 1,24 10L24,10A10,10 0,0 1,14 20L10,20A10,10 0,0 1,0 10L0,10A10,10 0,0 1,10 0z"
|
||||
android:fillColor="@android:color/white"/>
|
||||
</vector>
|
||||
16
packages/SystemUI/res/drawable/stat_sys_screen_record.xml
Normal file
16
packages/SystemUI/res/drawable/stat_sys_screen_record.xml
Normal file
@@ -0,0 +1,16 @@
|
||||
<!--
|
||||
Copyright (C) 2020 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<com.android.systemui.statusbar.ScreenRecordDrawable />
|
||||
18
packages/SystemUI/res/drawable/stat_sys_screen_record_1.xml
Normal file
18
packages/SystemUI/res/drawable/stat_sys_screen_record_1.xml
Normal file
@@ -0,0 +1,18 @@
|
||||
<!--
|
||||
Copyright (C) 2020 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<com.android.systemui.statusbar.ScreenRecordDrawable
|
||||
level="1"
|
||||
/>
|
||||
18
packages/SystemUI/res/drawable/stat_sys_screen_record_2.xml
Normal file
18
packages/SystemUI/res/drawable/stat_sys_screen_record_2.xml
Normal file
@@ -0,0 +1,18 @@
|
||||
<!--
|
||||
Copyright (C) 2020 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<com.android.systemui.statusbar.ScreenRecordDrawable
|
||||
level="2"
|
||||
/>
|
||||
18
packages/SystemUI/res/drawable/stat_sys_screen_record_3.xml
Normal file
18
packages/SystemUI/res/drawable/stat_sys_screen_record_3.xml
Normal file
@@ -0,0 +1,18 @@
|
||||
<!--
|
||||
Copyright (C) 2020 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<com.android.systemui.statusbar.ScreenRecordDrawable
|
||||
level="3"
|
||||
/>
|
||||
@@ -1228,6 +1228,8 @@
|
||||
<!-- Screen Record -->
|
||||
<dimen name="screenrecord_dialog_padding">18dp</dimen>
|
||||
<dimen name="screenrecord_logo_size">24dp</dimen>
|
||||
<dimen name="screenrecord_status_text_size">14sp</dimen>
|
||||
<dimen name="screenrecord_status_icon_radius">5dp</dimen>
|
||||
|
||||
<dimen name="kg_user_switcher_text_size">16sp</dimen>
|
||||
</resources>
|
||||
|
||||
@@ -31,20 +31,26 @@ import javax.inject.Inject;
|
||||
/**
|
||||
* Quick settings tile for screen recording
|
||||
*/
|
||||
public class ScreenRecordTile extends QSTileImpl<QSTile.BooleanState> {
|
||||
public class ScreenRecordTile extends QSTileImpl<QSTile.BooleanState>
|
||||
implements RecordingController.RecordingStateChangeCallback {
|
||||
private static final String TAG = "ScreenRecordTile";
|
||||
private RecordingController mController;
|
||||
private long mMillisUntilFinished = 0;
|
||||
private Callback mCallback = new Callback();
|
||||
|
||||
@Inject
|
||||
public ScreenRecordTile(QSHost host, RecordingController controller) {
|
||||
super(host);
|
||||
mController = controller;
|
||||
mController.observe(this, mCallback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BooleanState newTileState() {
|
||||
return new BooleanState();
|
||||
BooleanState state = new BooleanState();
|
||||
state.label = mContext.getString(R.string.quick_settings_screen_record_label);
|
||||
state.handlesLongClick = false;
|
||||
return state;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -59,24 +65,13 @@ public class ScreenRecordTile extends QSTileImpl<QSTile.BooleanState> {
|
||||
refreshState();
|
||||
}
|
||||
|
||||
/**
|
||||
* Refresh tile state
|
||||
* @param millisUntilFinished Time until countdown completes, or 0 if not counting down
|
||||
*/
|
||||
public void refreshState(long millisUntilFinished) {
|
||||
mMillisUntilFinished = millisUntilFinished;
|
||||
refreshState();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleUpdateState(BooleanState state, Object arg) {
|
||||
boolean isStarting = mController.isStarting();
|
||||
boolean isRecording = mController.isRecording();
|
||||
|
||||
state.label = mContext.getString(R.string.quick_settings_screen_record_label);
|
||||
state.value = isRecording || isStarting;
|
||||
state.state = (isRecording || isStarting) ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
|
||||
state.handlesLongClick = false;
|
||||
|
||||
if (isRecording) {
|
||||
state.icon = ResourceIcon.get(R.drawable.ic_qs_screenrecord);
|
||||
@@ -125,4 +120,22 @@ public class ScreenRecordTile extends QSTileImpl<QSTile.BooleanState> {
|
||||
Log.d(TAG, "Stopping recording from tile");
|
||||
mController.stopRecording();
|
||||
}
|
||||
|
||||
private final class Callback implements RecordingController.RecordingStateChangeCallback {
|
||||
@Override
|
||||
public void onCountdown(long millisUntilFinished) {
|
||||
mMillisUntilFinished = millisUntilFinished;
|
||||
refreshState();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRecordingStart() {
|
||||
refreshState();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRecordingEnd() {
|
||||
refreshState();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,9 @@ import android.os.CountDownTimer;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.systemui.qs.tiles.ScreenRecordTile;
|
||||
import com.android.systemui.statusbar.policy.CallbackController;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
@@ -32,7 +35,8 @@ import javax.inject.Singleton;
|
||||
* Helper class to initiate a screen recording
|
||||
*/
|
||||
@Singleton
|
||||
public class RecordingController {
|
||||
public class RecordingController
|
||||
implements CallbackController<RecordingController.RecordingStateChangeCallback> {
|
||||
private static final String TAG = "RecordingController";
|
||||
private static final String SYSUI_PACKAGE = "com.android.systemui";
|
||||
private static final String SYSUI_SCREENRECORD_LAUNCHER =
|
||||
@@ -41,10 +45,11 @@ public class RecordingController {
|
||||
private final Context mContext;
|
||||
private boolean mIsStarting;
|
||||
private boolean mIsRecording;
|
||||
private ScreenRecordTile mTileToUpdate;
|
||||
private PendingIntent mStopIntent;
|
||||
private CountDownTimer mCountDownTimer = null;
|
||||
|
||||
private ArrayList<RecordingStateChangeCallback> mListeners = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Create a new RecordingController
|
||||
* @param context Context for the controller
|
||||
@@ -63,10 +68,7 @@ public class RecordingController {
|
||||
final Intent intent = new Intent();
|
||||
intent.setComponent(launcherComponent);
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
intent.putExtra("com.android.systemui.screenrecord.EXTRA_SETTINGS_ONLY", true);
|
||||
mContext.startActivity(intent);
|
||||
|
||||
mTileToUpdate = tileToUpdate;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -82,16 +84,21 @@ public class RecordingController {
|
||||
mCountDownTimer = new CountDownTimer(ms, 1000) {
|
||||
@Override
|
||||
public void onTick(long millisUntilFinished) {
|
||||
refreshTile(millisUntilFinished);
|
||||
for (RecordingStateChangeCallback cb : mListeners) {
|
||||
cb.onCountdown(millisUntilFinished);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFinish() {
|
||||
mIsStarting = false;
|
||||
mIsRecording = true;
|
||||
refreshTile();
|
||||
for (RecordingStateChangeCallback cb : mListeners) {
|
||||
cb.onRecordingEnd();
|
||||
}
|
||||
try {
|
||||
startIntent.send();
|
||||
Log.d(TAG, "sent start intent");
|
||||
} catch (PendingIntent.CanceledException e) {
|
||||
Log.e(TAG, "Pending intent was cancelled: " + e.getMessage());
|
||||
}
|
||||
@@ -101,18 +108,6 @@ public class RecordingController {
|
||||
mCountDownTimer.start();
|
||||
}
|
||||
|
||||
private void refreshTile() {
|
||||
refreshTile(0);
|
||||
}
|
||||
|
||||
private void refreshTile(long millisUntilFinished) {
|
||||
if (mTileToUpdate != null) {
|
||||
mTileToUpdate.refreshState(millisUntilFinished);
|
||||
} else {
|
||||
Log.e(TAG, "No tile to refresh");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel a countdown in progress. This will not stop the recording if it already started.
|
||||
*/
|
||||
@@ -123,7 +118,10 @@ public class RecordingController {
|
||||
Log.e(TAG, "Timer was null");
|
||||
}
|
||||
mIsStarting = false;
|
||||
refreshTile();
|
||||
|
||||
for (RecordingStateChangeCallback cb : mListeners) {
|
||||
cb.onRecordingEnd();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -152,7 +150,10 @@ public class RecordingController {
|
||||
} catch (PendingIntent.CanceledException e) {
|
||||
Log.e(TAG, "Error stopping: " + e.getMessage());
|
||||
}
|
||||
refreshTile();
|
||||
|
||||
for (RecordingStateChangeCallback cb : mListeners) {
|
||||
cb.onRecordingEnd();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -161,6 +162,44 @@ public class RecordingController {
|
||||
*/
|
||||
public void updateState(boolean isRecording) {
|
||||
mIsRecording = isRecording;
|
||||
refreshTile();
|
||||
for (RecordingStateChangeCallback cb : mListeners) {
|
||||
if (isRecording) {
|
||||
cb.onRecordingStart();
|
||||
} else {
|
||||
cb.onRecordingEnd();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addCallback(RecordingStateChangeCallback listener) {
|
||||
mListeners.add(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeCallback(RecordingStateChangeCallback listener) {
|
||||
mListeners.remove(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* A callback for changes in the screen recording state
|
||||
*/
|
||||
public interface RecordingStateChangeCallback {
|
||||
/**
|
||||
* Called when a countdown to recording has updated
|
||||
*
|
||||
* @param millisUntilFinished Time in ms remaining in the countdown
|
||||
*/
|
||||
default void onCountdown(long millisUntilFinished) {}
|
||||
|
||||
/**
|
||||
* Called when a screen recording has started
|
||||
*/
|
||||
default void onRecordingStart() {}
|
||||
|
||||
/**
|
||||
* Called when a screen recording has ended
|
||||
*/
|
||||
default void onRecordingEnd() {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.systemui.statusbar;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.graphics.drawable.DrawableWrapper;
|
||||
import android.util.AttributeSet;
|
||||
|
||||
import com.android.systemui.R;
|
||||
|
||||
import org.xmlpull.v1.XmlPullParser;
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* The screen record drawable draws a colored background and either a countdown or circle to
|
||||
* indicate that the screen is being recorded.
|
||||
*/
|
||||
public class ScreenRecordDrawable extends DrawableWrapper {
|
||||
private Drawable mFillDrawable;
|
||||
private int mHorizontalPadding;
|
||||
private int mLevel;
|
||||
private float mTextSize;
|
||||
private float mIconRadius;
|
||||
private Paint mPaint;
|
||||
|
||||
/** No-arg constructor used by drawable inflation. */
|
||||
public ScreenRecordDrawable() {
|
||||
super(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void inflate(@NonNull Resources r, @NonNull XmlPullParser parser,
|
||||
@NonNull AttributeSet attrs, @Nullable Resources.Theme theme)
|
||||
throws XmlPullParserException, IOException {
|
||||
super.inflate(r, parser, attrs, theme);
|
||||
setDrawable(r.getDrawable(R.drawable.ic_screen_record_background, theme).mutate());
|
||||
mFillDrawable = r.getDrawable(R.drawable.ic_screen_record_background, theme).mutate();
|
||||
mHorizontalPadding = r.getDimensionPixelSize(R.dimen.status_bar_horizontal_padding);
|
||||
|
||||
mTextSize = r.getDimensionPixelSize(R.dimen.screenrecord_status_text_size);
|
||||
mIconRadius = r.getDimensionPixelSize(R.dimen.screenrecord_status_icon_radius);
|
||||
mLevel = attrs.getAttributeIntValue(null, "level", 0);
|
||||
|
||||
mPaint = new Paint();
|
||||
mPaint.setTextAlign(Paint.Align.CENTER);
|
||||
mPaint.setColor(Color.WHITE);
|
||||
mPaint.setTextSize(mTextSize);
|
||||
mPaint.setFakeBoldText(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canApplyTheme() {
|
||||
return mFillDrawable.canApplyTheme() || super.canApplyTheme();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyTheme(Resources.Theme t) {
|
||||
super.applyTheme(t);
|
||||
mFillDrawable.applyTheme(t);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onBoundsChange(Rect bounds) {
|
||||
super.onBoundsChange(bounds);
|
||||
mFillDrawable.setBounds(bounds);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onLayoutDirectionChanged(int layoutDirection) {
|
||||
mFillDrawable.setLayoutDirection(layoutDirection);
|
||||
return super.onLayoutDirectionChanged(layoutDirection);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Canvas canvas) {
|
||||
super.draw(canvas);
|
||||
mFillDrawable.draw(canvas);
|
||||
|
||||
Rect b = mFillDrawable.getBounds();
|
||||
if (mLevel > 0) {
|
||||
String val = String.valueOf(mLevel);
|
||||
Rect textBounds = new Rect();
|
||||
mPaint.getTextBounds(val, 0, val.length(), textBounds);
|
||||
float yOffset = textBounds.height() / 4; // half, and half again since it's centered
|
||||
canvas.drawText(val, b.centerX(), b.centerY() + yOffset, mPaint);
|
||||
} else {
|
||||
canvas.drawCircle(b.centerX(), b.centerY() - mIconRadius / 2, mIconRadius, mPaint);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getPadding(Rect padding) {
|
||||
padding.left += mHorizontalPadding;
|
||||
padding.right += mHorizontalPadding;
|
||||
padding.top = 0;
|
||||
padding.bottom = 0;
|
||||
android.util.Log.d("ScreenRecordDrawable", "set zero top/bottom pad");
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAlpha(int alpha) {
|
||||
super.setAlpha(alpha);
|
||||
mFillDrawable.setAlpha(alpha);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setVisible(boolean visible, boolean restart) {
|
||||
mFillDrawable.setVisible(visible, restart);
|
||||
return super.setVisible(visible, restart);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Drawable mutate() {
|
||||
mFillDrawable.mutate();
|
||||
return super.mutate();
|
||||
}
|
||||
}
|
||||
@@ -43,6 +43,7 @@ import com.android.systemui.broadcast.BroadcastDispatcher;
|
||||
import com.android.systemui.dagger.qualifiers.UiBackground;
|
||||
import com.android.systemui.qs.tiles.DndTile;
|
||||
import com.android.systemui.qs.tiles.RotationLockTile;
|
||||
import com.android.systemui.screenrecord.RecordingController;
|
||||
import com.android.systemui.statusbar.CommandQueue;
|
||||
import com.android.systemui.statusbar.policy.BluetoothController;
|
||||
import com.android.systemui.statusbar.policy.CastController;
|
||||
@@ -76,7 +77,8 @@ public class PhoneStatusBarPolicy
|
||||
ZenModeController.Callback,
|
||||
DeviceProvisionedListener,
|
||||
KeyguardStateController.Callback,
|
||||
LocationController.LocationChangeCallback {
|
||||
LocationController.LocationChangeCallback,
|
||||
RecordingController.RecordingStateChangeCallback {
|
||||
private static final String TAG = "PhoneStatusBarPolicy";
|
||||
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
|
||||
|
||||
@@ -98,6 +100,7 @@ public class PhoneStatusBarPolicy
|
||||
private final String mSlotMicrophone;
|
||||
private final String mSlotCamera;
|
||||
private final String mSlotSensorsOff;
|
||||
private final String mSlotScreenRecord;
|
||||
|
||||
private final Context mContext;
|
||||
private final Handler mHandler = new Handler();
|
||||
@@ -116,6 +119,7 @@ public class PhoneStatusBarPolicy
|
||||
private final LocationController mLocationController;
|
||||
private final Executor mUiBgExecutor;
|
||||
private final SensorPrivacyController mSensorPrivacyController;
|
||||
private final RecordingController mRecordingController;
|
||||
|
||||
// Assume it's all good unless we hear otherwise. We don't always seem
|
||||
// to get broadcasts that it *is* there.
|
||||
@@ -149,6 +153,7 @@ public class PhoneStatusBarPolicy
|
||||
mKeyguardStateController = Dependency.get(KeyguardStateController.class);
|
||||
mLocationController = Dependency.get(LocationController.class);
|
||||
mSensorPrivacyController = Dependency.get(SensorPrivacyController.class);
|
||||
mRecordingController = Dependency.get(RecordingController.class);
|
||||
mUiBgExecutor = uiBgExecutor;
|
||||
|
||||
mSlotCast = context.getString(com.android.internal.R.string.status_bar_cast);
|
||||
@@ -167,6 +172,8 @@ public class PhoneStatusBarPolicy
|
||||
mSlotMicrophone = context.getString(com.android.internal.R.string.status_bar_microphone);
|
||||
mSlotCamera = context.getString(com.android.internal.R.string.status_bar_camera);
|
||||
mSlotSensorsOff = context.getString(com.android.internal.R.string.status_bar_sensors_off);
|
||||
mSlotScreenRecord = context.getString(
|
||||
com.android.internal.R.string.status_bar_screen_record);
|
||||
|
||||
// listen for broadcasts
|
||||
IntentFilter filter = new IntentFilter();
|
||||
@@ -235,6 +242,10 @@ public class PhoneStatusBarPolicy
|
||||
mIconController.setIconVisibility(mSlotSensorsOff,
|
||||
mSensorPrivacyController.isSensorPrivacyEnabled());
|
||||
|
||||
// screen record
|
||||
mIconController.setIcon(mSlotScreenRecord, R.drawable.stat_sys_screen_record, null);
|
||||
mIconController.setIconVisibility(mSlotScreenRecord, false);
|
||||
|
||||
mRotationLockController.addCallback(this);
|
||||
mBluetooth.addCallback(this);
|
||||
mProvisionedController.addCallback(this);
|
||||
@@ -246,6 +257,7 @@ public class PhoneStatusBarPolicy
|
||||
mKeyguardStateController.addCallback(this);
|
||||
mSensorPrivacyController.addCallback(mSensorPrivacyListener);
|
||||
mLocationController.addCallback(this);
|
||||
mRecordingController.addCallback(this);
|
||||
|
||||
commandQueue.addCallback(this);
|
||||
}
|
||||
@@ -438,7 +450,7 @@ public class PhoneStatusBarPolicy
|
||||
}
|
||||
if (DEBUG) Log.v(TAG, "updateCast: isCasting: " + isCasting);
|
||||
mHandler.removeCallbacks(mRemoveCastIconRunnable);
|
||||
if (isCasting) {
|
||||
if (isCasting && !mRecordingController.isRecording()) { // screen record has its own icon
|
||||
mIconController.setIcon(mSlotCast, R.drawable.stat_sys_cast,
|
||||
mContext.getString(R.string.accessibility_casting));
|
||||
mIconController.setIconVisibility(mSlotCast, true);
|
||||
@@ -643,4 +655,40 @@ public class PhoneStatusBarPolicy
|
||||
mIconController.setIconVisibility(mSlotCast, false);
|
||||
}
|
||||
};
|
||||
|
||||
// Screen Recording
|
||||
@Override
|
||||
public void onCountdown(long millisUntilFinished) {
|
||||
if (DEBUG) Log.d(TAG, "screenrecord: countdown " + millisUntilFinished);
|
||||
int countdown = (int) Math.floorDiv(millisUntilFinished + 500, 1000);
|
||||
int resourceId = R.drawable.stat_sys_screen_record;
|
||||
switch (countdown) {
|
||||
case 1:
|
||||
resourceId = R.drawable.stat_sys_screen_record_1;
|
||||
break;
|
||||
case 2:
|
||||
resourceId = R.drawable.stat_sys_screen_record_2;
|
||||
break;
|
||||
case 3:
|
||||
resourceId = R.drawable.stat_sys_screen_record_3;
|
||||
break;
|
||||
}
|
||||
mIconController.setIcon(mSlotScreenRecord, resourceId, null);
|
||||
mIconController.setIconVisibility(mSlotScreenRecord, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRecordingStart() {
|
||||
if (DEBUG) Log.d(TAG, "screenrecord: showing icon");
|
||||
mIconController.setIcon(mSlotScreenRecord,
|
||||
R.drawable.stat_sys_screen_record, null);
|
||||
mIconController.setIconVisibility(mSlotScreenRecord, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRecordingEnd() {
|
||||
// Ensure this is on the main thread, since it could be called during countdown
|
||||
if (DEBUG) Log.d(TAG, "screenrecord: hiding icon");
|
||||
mHandler.post(() -> mIconController.setIconVisibility(mSlotScreenRecord, false));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user