diff --git a/res/drawable/icon_mute.xml b/res/drawable/icon_mute.xml new file mode 100644 index 0000000..20cf37b --- /dev/null +++ b/res/drawable/icon_mute.xml @@ -0,0 +1,20 @@ + + + + diff --git a/res/layout/window_mute_prompt.xml b/res/layout/window_mute_prompt.xml new file mode 100644 index 0000000..2af0064 --- /dev/null +++ b/res/layout/window_mute_prompt.xml @@ -0,0 +1,13 @@ + + + + + diff --git a/src/com/android/systemui/SystemUIApplication.java b/src/com/android/systemui/SystemUIApplication.java index 191ac76..924b287 100644 --- a/src/com/android/systemui/SystemUIApplication.java +++ b/src/com/android/systemui/SystemUIApplication.java @@ -79,6 +79,11 @@ public class SystemUIApplication extends Application implements private SystemUIAppComponentFactory.ContextAvailableCallback mContextAvailableCallback; private SysUIComponent mSysUIComponent; private SystemUIInitializer mInitializer; + private static SystemUIApplication sSystemUIApplication = null; + + public static SystemUIApplication getInstance(){ + return sSystemUIApplication; + } public SystemUIApplication() { super(); @@ -94,6 +99,7 @@ public class SystemUIApplication extends Application implements @Override public void onCreate() { super.onCreate(); + sSystemUIApplication = this; Log.v(TAG, "SystemUIApplication created."); // This line is used to setup Dagger's dependency injection and should be kept at the // top of this method. diff --git a/src/com/android/systemui/volume/VolumeDialogControllerImpl.java b/src/com/android/systemui/volume/VolumeDialogControllerImpl.java index 98d904e..3b6b750 100644 --- a/src/com/android/systemui/volume/VolumeDialogControllerImpl.java +++ b/src/com/android/systemui/volume/VolumeDialogControllerImpl.java @@ -81,6 +81,10 @@ import java.util.Map; import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; +import android.media.AudioDeviceCallback; +import android.media.AudioDeviceInfo; +import com.zeasn.whaleos.view.MutePromptFloatWindow; + import javax.inject.Inject; /** @@ -147,7 +151,9 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa private VolumePolicy mVolumePolicy; @GuardedBy("this") private UserActivityListener mUserActivityListener; - + private MutePromptFloatWindow mutePromptFloatWindow; + private boolean mIsShowMuteIcon = true; + protected final VC mVolumeController = new VC(); protected final BroadcastDispatcher mBroadcastDispatcher; @@ -218,6 +224,12 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa VolumePolicy.A11Y_MODE_MEDIA_A11Y_VOLUME); mWakefulnessLifecycle.addObserver(mWakefullnessLifecycleObserver); + //add zeasn regster code + if (null == mutePromptFloatWindow) { + mutePromptFloatWindow = new MutePromptFloatWindow(); + mutePromptFloatWindow.hide(); + } + mAudio.registerAudioDeviceCallback(callback, new Handler()); } public AudioManager getAudioManager() { @@ -1119,6 +1131,17 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa } if (changed) { mCallbacks.onStateChanged(mState); + new Handler(Looper.getMainLooper()).post(new Runnable() { + @Override + public void run() { + updateState(); + } + }); + //********************* add zeasn audio receiver start + Intent zeasnIntent = new Intent("com.zeasn.action.DEVICE_AUDIO_CHANGED"); + zeasnIntent.setComponent(new ComponentName("com.zeasn.whaleos.launcher3","com.zeasn.whaleos.launcher.receiver.VolumeChangeReceiver")); + context.sendBroadcast(zeasnIntent); + //********************* add zeasn audio receiver end } } } @@ -1274,4 +1297,66 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa public interface UserActivityListener { void onUserActivity(); } + + //****************************** add zeasn audio code start ************************************ + + private AudioDeviceCallback callback = new AudioDeviceCallback() { + private void updateNrdpProfile(AudioDeviceInfo[] devices, boolean state) { + for (AudioDeviceInfo deviceInfo : devices) { + Log.d(TAG, "isSink = " + deviceInfo.isSink() + ", " + (state ? "connect" : "disconnect") + " Audio device: " + deviceInfo.getType()); + if (deviceInfo.isSink() && (deviceInfo.getType() == AudioDeviceInfo.TYPE_HDMI_ARC)) { + Log.d(TAG, (state ? "connect" : "disconnect") + " Audio device: " + deviceInfo.getType()); + if (state) { + Log.d(TAG, "arc device added "); + mIsShowMuteIcon = false; + updateState(); + } else { + Log.d(TAG, "arc device removed "); + mIsShowMuteIcon = true; + updateState(); + } + return; + } + } + } + + @Override + public void onAudioDevicesAdded(AudioDeviceInfo[] addedDevices) { + super.onAudioDevicesAdded(addedDevices); + Log.d(TAG, "audio device added "); + updateNrdpProfile(addedDevices, true); + } + + @Override + public void onAudioDevicesRemoved(AudioDeviceInfo[] removedDevices) { + Log.d(TAG, "audio device removed "); + updateNrdpProfile(removedDevices, false); + } + }; + + private void updateState() { + Log.d(TAG, "updateState: mIsShowMuteIcon -> " + mIsShowMuteIcon); + if (mIsShowMuteIcon) { + boolean isMute = getSystemVolume(); + Log.d(TAG, "updateState: isMute -> " + isMute); + if (isMute) { + if (!mutePromptFloatWindow.isShown()) { + mutePromptFloatWindow.show(); + } + } else { + if (mutePromptFloatWindow.isShown()) { + mutePromptFloatWindow.hide(); + } + } + } else { + if (mutePromptFloatWindow.isShown()) { + mutePromptFloatWindow.hide(); + } + } + } + + private boolean getSystemVolume() { + return mAudio.isStreamMute(AudioManager.STREAM_MUSIC); + } + // *********************************** add zeasn audio code end **************************** } diff --git a/src/com/lib/common/base/window/DisplayType.java b/src/com/lib/common/base/window/DisplayType.java new file mode 100644 index 0000000..6e1d02b --- /dev/null +++ b/src/com/lib/common/base/window/DisplayType.java @@ -0,0 +1,27 @@ +package com.lib.common.base.window; + +/** + * =================================================== + * Created by MackWu on 2021/7/27 14:55 + * Contact me + * Follow me + * =================================================== + */ +public enum DisplayType { + + /** + * 显示和隐藏 + */ + SHOW_AND_HIDE, + + /** + * 1px和全屏 + */ + @Deprecated + ONE_PX_AND_MATCH_PARENT, + + /** + * 移到屏幕外 + */ + OUT_OF_SCREEN, +} diff --git a/src/com/lib/common/base/window/IWindow.java b/src/com/lib/common/base/window/IWindow.java new file mode 100644 index 0000000..29561c4 --- /dev/null +++ b/src/com/lib/common/base/window/IWindow.java @@ -0,0 +1,74 @@ +package com.lib.common.base.window; + +/** + * =================================================== + * Created by MackWu on 2020/8/3 19:24 + * Contact me + * Follow me + * =================================================== + */ +public interface IWindow { + + /** + * 获取布局id + */ + int getLayoutId(); + + /** + * 类型 + * See {@link android.view.WindowManager.LayoutParams} + */ + int getType(); + + /** + * 位置 + */ + int getGravity(); + + /** + * flag + * + * @param isFocusable 是否有焦点 + */ + int getFlag(boolean isFocusable); + + /** + * 宽 + */ + int getWidth(); + + /** + * 高 + */ + int getHeight(); + + /** + * 在屏幕外时的X坐标 + */ + int getOutOfScreenX(); + + /** + * 在屏幕外时的Y坐标 + */ + int getOutOfScreenY(); + + /** + * 显示类型。 + */ + DisplayType getDisplayType(); + + /** + * 显示弹窗。 + */ + void show(); + + /** + * 隐藏弹窗。 + */ + void hide(); + + /** + * 是否显示 + */ + boolean isShown(); +} diff --git a/src/com/lib/common/base/window/base/BaseWindow.java b/src/com/lib/common/base/window/base/BaseWindow.java new file mode 100644 index 0000000..faf4e85 --- /dev/null +++ b/src/com/lib/common/base/window/base/BaseWindow.java @@ -0,0 +1,161 @@ +package com.lib.common.base.window.base; + +import android.content.Context; +import android.graphics.PixelFormat; +import android.os.Handler; +import android.os.Looper; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.View; +import android.view.WindowManager; + +import com.lib.common.base.window.DisplayType; +import com.lib.common.base.window.IWindow; +import com.android.systemui.SystemUIApplication; + +/** + * =================================================== + * Created by MackWu on 2020/8/3 19:23 + * Contact me + * Follow me + * =================================================== + */ +public abstract class BaseWindow implements IWindow { + + private boolean inited; + protected Context context; + protected WindowManager windowManager; + protected WindowManager.LayoutParams windowLayoutParams; + protected View view; + protected boolean isShown; + protected final Handler handler = new Handler(Looper.getMainLooper()); + + public BaseWindow() { + this(SystemUIApplication.getInstance()); + } + + public BaseWindow(Context context){ + this.context = context; + } + + public BaseWindow init(){ + if(!inited){ + inited=true; + this.windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); + this.windowLayoutParams = new WindowManager.LayoutParams(); + initView(); + initWindow(); + } + return this; + } + + protected abstract void onConfig(WindowManager.LayoutParams windowLayoutParams); + + protected void initView() { + this.view = LayoutInflater.from(context).inflate(getLayoutId(), null); + } + + protected void initWindow() { + windowLayoutParams.type = getType(); + windowLayoutParams.format = PixelFormat.TRANSLUCENT; + windowLayoutParams.gravity = getGravity(); + windowLayoutParams.flags = getFlag(true); + windowLayoutParams.width = getWidth(); + windowLayoutParams.height = getHeight(); + onConfig(this.windowLayoutParams); + windowManager.addView(view, windowLayoutParams); + hide(); + } + + @Override + public int getType() { + return WindowManager.LayoutParams.TYPE_APPLICATION; + } + + @Override + public int getGravity() { + return Gravity.BOTTOM | Gravity.END; + } + + @Override + public int getFlag(boolean isFocusable) { + return isFocusable + ? WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM | + WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | + WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH | + WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS + : WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | + WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE | + WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS; + } + + @Override + public int getWidth() { + return WindowManager.LayoutParams.MATCH_PARENT; + } + + @Override + public int getHeight() { + return WindowManager.LayoutParams.MATCH_PARENT; + } + + @Override + public int getOutOfScreenX() { + return -2000; + } + + @Override + public int getOutOfScreenY() { + return -2000; + } + + @Override + public DisplayType getDisplayType() { + return DisplayType.SHOW_AND_HIDE; + } + + @Override + public void show() { + isShown = true; + if (getDisplayType() == DisplayType.SHOW_AND_HIDE) { + view.setVisibility(View.VISIBLE); + } + if (getDisplayType() == DisplayType.OUT_OF_SCREEN) { + updateWindowPosition(0, 0, true); + } + } + + @Override + public void hide() { + isShown = false; + if (getDisplayType() == DisplayType.SHOW_AND_HIDE) { + view.setVisibility(View.GONE); + } + if (getDisplayType() == DisplayType.OUT_OF_SCREEN) { + updateWindowPosition(getOutOfScreenX(), getOutOfScreenY(), false); + } + } + + @Override + public boolean isShown() { + return isShown; + } + + protected void updateWindowPosition(int x, int y, boolean isFocusable) { + windowLayoutParams = new WindowManager.LayoutParams(); + windowLayoutParams.type = getType(); + windowLayoutParams.format = PixelFormat.TRANSLUCENT; + windowLayoutParams.gravity = getGravity(); + windowLayoutParams.flags = getFlag(isFocusable); + windowLayoutParams.x = x; + windowLayoutParams.y = y; + windowLayoutParams.width = getWidth(); + windowLayoutParams.height = getHeight(); + windowManager.updateViewLayout(view, windowLayoutParams); + } + + public void remove(){ + windowManager.removeView(view); + } + +} diff --git a/src/com/lib/common/base/window/base/FloatView.java b/src/com/lib/common/base/window/base/FloatView.java new file mode 100644 index 0000000..3f327f3 --- /dev/null +++ b/src/com/lib/common/base/window/base/FloatView.java @@ -0,0 +1,43 @@ +package com.lib.common.base.window.base; + +import android.view.View; +import android.view.WindowManager; + +/** + */ + +public abstract class FloatView { + + abstract void setSize(int width, int height); + + abstract void setView(View view); + + abstract void setGravity(int gravity, int xOffset, int yOffset); + + public abstract FloatView init(); + + public abstract FloatView setFlag(int flag); + + abstract void dismiss(); + + public void updateXY(int x, int y) { + } + + void updateX(int x) { + } + + void updateY(int y) { + } + + public int getX() { + return 0; + } + + public int getY() { + return 0; + } + + public void updateViewLayout(WindowManager.LayoutParams windowLayoutParams) { + + } +} \ No newline at end of file diff --git a/src/com/lib/common/base/window/base/FloatWindow.java b/src/com/lib/common/base/window/base/FloatWindow.java new file mode 100644 index 0000000..61f3b3f --- /dev/null +++ b/src/com/lib/common/base/window/base/FloatWindow.java @@ -0,0 +1,107 @@ +package com.lib.common.base.window.base; + +import android.content.Context; +import android.graphics.PixelFormat; +import android.view.View; +import android.view.WindowManager; + +/** + */ + +public class FloatWindow extends FloatView { + + private final Context mContext; + + private final WindowManager mWindowManager; + private final WindowManager.LayoutParams mLayoutParams; + private View mView; + private int mX, mY; + private boolean isRemove = false; + + public FloatWindow(Context applicationContext, int windowType) { + mContext = applicationContext; + mWindowManager = (WindowManager) applicationContext.getSystemService(Context.WINDOW_SERVICE); + mLayoutParams = new WindowManager.LayoutParams(); + mLayoutParams.type = windowType; + mLayoutParams.format = PixelFormat.TRANSLUCENT; + mLayoutParams.width = WindowManager.LayoutParams.WRAP_CONTENT; + mLayoutParams.height = WindowManager.LayoutParams.WRAP_CONTENT; + mLayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | + WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | + WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | + WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH; + } + + @Override + public void setSize(int width, int height) { + + } + + @Override + public void setView(View view) { + mView = view; + } + + + @Override + public void setGravity(int gravity, int xOffset, int yOffset) { + mLayoutParams.gravity = gravity; + mLayoutParams.x = mX = xOffset; + mLayoutParams.y = mY = yOffset; + } + + @Override + public FloatView init() { + try { + mWindowManager.addView(mView, mLayoutParams); + } catch (Exception ignored) { + } + return this; + } + + @Override + public FloatView setFlag(int flag){ + mLayoutParams.flags = flag; + return this; + } + + @Override + public void dismiss() { + isRemove = true; + mWindowManager.removeView(mView); + } + + @Override + public void updateXY(int x, int y) { + if (isRemove) return; + mLayoutParams.x = mX = x; + mLayoutParams.y = mY = y; + mWindowManager.updateViewLayout(mView, mLayoutParams); + } + + @Override + void updateX(int x) { + if (isRemove) return; + mLayoutParams.x = mX = x; + mWindowManager.updateViewLayout(mView, mLayoutParams); + } + + @Override + void updateY(int y) { + if (isRemove) return; + mLayoutParams.y = mY = y; + mWindowManager.updateViewLayout(mView, mLayoutParams); + } + + @Override + public int getX() { + return mX; + } + + @Override + public int getY() { + return mY; + } + + +} \ No newline at end of file diff --git a/src/com/zeasn/whaleos/view/MutePromptFloatWindow.java b/src/com/zeasn/whaleos/view/MutePromptFloatWindow.java new file mode 100644 index 0000000..91b7d9c --- /dev/null +++ b/src/com/zeasn/whaleos/view/MutePromptFloatWindow.java @@ -0,0 +1,50 @@ +package com.zeasn.whaleos.view; + +import android.view.Gravity; +import android.view.WindowManager; + +import com.lib.common.base.window.base.BaseWindow; +import com.android.systemui.R; + +public class MutePromptFloatWindow extends BaseWindow { + + public MutePromptFloatWindow() { + super(); + init(); + } + + @Override + protected void onConfig(WindowManager.LayoutParams windowLayoutParams) { + windowLayoutParams.flags = getFlag(false); + } + + @Override + public int getLayoutId() { + return R.layout.window_mute_prompt; + } + + @Override + public int getType() { + return WindowManager.LayoutParams.TYPE_SEARCH_BAR; + } + + @Override + public int getGravity() { + return Gravity.TOP | Gravity.END; + } + + @Override + public int getWidth() { + return WindowManager.LayoutParams.WRAP_CONTENT; + } + + @Override + public int getHeight() { + return WindowManager.LayoutParams.WRAP_CONTENT; + } + + @Override + public void show() { + super.show(); + } +}