FloatingButton: support call control
Signed-off-by: cjybyjk <cjybyjk@zjnu.edu.cn>
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 54dac14..092ae70 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -9,6 +9,7 @@
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.MODIFY_PHONE_STATE" />
+ <uses-permission android:name="android.permission.ANSWER_PHONE_CALLS" />
<uses-permission android:name="android.permission.PROCESS_INCOMING_CALLS" />
<application
diff --git a/app/src/main/java/org/exthmui/game/misc/Constants.java b/app/src/main/java/org/exthmui/game/misc/Constants.java
index 911c67b..5136639 100644
--- a/app/src/main/java/org/exthmui/game/misc/Constants.java
+++ b/app/src/main/java/org/exthmui/game/misc/Constants.java
@@ -38,6 +38,11 @@
*/
public static final String BROADCAST_GAMING_ACTION = "org.exthmui.game.GAMING_ACTION";
public static final String BROADCAST_GAMING_MENU_CONTROL = "org.exthmui.game.GAMING_MENU_CONTROL";
+
+ /* 来电状态与控制 */
+ public static final String BROADCAST_CALL_STATUS = "org.exthmui.game.CALL_STATUS";
+ // cmd: 1=挂断 2=接听
+ public static final String BROADCAST_CALL_CONTROL = "org.exthmui.game.CALL_CONTROL";
}
public static class ConfigKeys {
diff --git a/app/src/main/java/org/exthmui/game/services/GamingService.java b/app/src/main/java/org/exthmui/game/services/GamingService.java
index 936e99f..272c659 100644
--- a/app/src/main/java/org/exthmui/game/services/GamingService.java
+++ b/app/src/main/java/org/exthmui/game/services/GamingService.java
@@ -68,6 +68,8 @@
private Intent mOverlayServiceIntent;
private Notification mGamingNotification;
+ private Intent mCallStatusIntent;
+
private String mCurrentPackage;
private Bundle mCurrentConfig = new Bundle();
@@ -89,6 +91,18 @@
}
};
+ private BroadcastReceiver mCallControlReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (mTelecomManager == null) return;
+ if (intent.getIntExtra("cmd", 1) == 1) {
+ mTelecomManager.endCall();
+ } else {
+ mTelecomManager.acceptRingingCall();
+ }
+ }
+ };
+
private BroadcastReceiver mGamingActionReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -137,11 +151,14 @@
}
registerReceiver(mGamingModeOffReceiver, new IntentFilter(Constants.Broadcasts.SYS_BROADCAST_GAMING_MODE_OFF));
+ LocalBroadcastManager.getInstance(this).registerReceiver(mCallControlReceiver, new IntentFilter(Constants.Broadcasts.BROADCAST_CALL_CONTROL));
LocalBroadcastManager.getInstance(this).registerReceiver(mGamingActionReceiver, new IntentFilter(Constants.Broadcasts.BROADCAST_GAMING_ACTION));
mPhoneStateListener = new GamingPhoneStateListener();
mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
+ mCallStatusIntent = new Intent(Constants.Broadcasts.BROADCAST_CALL_STATUS);
+
mOverlayServiceIntent = new Intent(this, OverlayService.class);
PendingIntent stopGamingIntent = PendingIntent.getBroadcast(this, 0, new Intent(Constants.Broadcasts.SYS_BROADCAST_GAMING_MODE_OFF), 0);
@@ -167,6 +184,10 @@
mOverlayServiceIntent.putExtras(mCurrentConfig);
startServiceAsUser(mOverlayServiceIntent, UserHandle.CURRENT);
Settings.System.putInt(getContentResolver(), Settings.System.GAMING_MODE_ACTIVE, 1);
+ if (mTelephonyManager != null) {
+ mCallStatusIntent.putExtra("state", mTelephonyManager.getCallState());
+ LocalBroadcastManager.getInstance(this).sendBroadcast(mCallStatusIntent);
+ }
return super.onStartCommand(intent, flags, startId);
}
@@ -310,6 +331,7 @@
@Override
public void onDestroy() {
unregisterReceiver(mGamingModeOffReceiver);
+ LocalBroadcastManager.getInstance(this).unregisterReceiver(mCallControlReceiver);
stopServiceAsUser(mOverlayServiceIntent, UserHandle.CURRENT);
mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE);
setDisableGesture(false);
@@ -398,6 +420,8 @@
break;
}
}
+ mCallStatusIntent.putExtra("state", state);
+ LocalBroadcastManager.getInstance(GamingService.this).sendBroadcast(mCallStatusIntent);
mPrevState = state;
super.onCallStateChanged(state, phoneNumber);
}
diff --git a/app/src/main/java/org/exthmui/game/services/OverlayService.java b/app/src/main/java/org/exthmui/game/services/OverlayService.java
index 439c33d..ddf92fe 100644
--- a/app/src/main/java/org/exthmui/game/services/OverlayService.java
+++ b/app/src/main/java/org/exthmui/game/services/OverlayService.java
@@ -27,6 +27,7 @@
import android.os.IBinder;
import android.preference.PreferenceManager;
import android.provider.Settings;
+import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.view.Gravity;
import android.view.LayoutInflater;
@@ -35,6 +36,7 @@
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.FrameLayout;
+import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ScrollView;
@@ -54,7 +56,9 @@
private static final String TAG = "OverlayService";
- private View mGamingFloatingButton;
+ private View mGamingFloatingLayout;
+ private ImageView mGamingFloatingButton;
+ private ImageView mCallControlButton;
private LinearLayout mGamingOverlayView;
private ScrollView mGamingMenu;
private FrameLayout mDanmakuContainer;
@@ -70,6 +74,8 @@
private Bundle configBundle;
+ private int mCallStatus = TelephonyManager.CALL_STATE_IDLE;
+
private OMReceiver mOMReceiver = new OMReceiver();
private BroadcastReceiver mSysConfigChangedReceiver = new BroadcastReceiver() {
@Override
@@ -78,6 +84,27 @@
}
};
+ private BroadcastReceiver mCallStatusReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (mCallControlButton == null) return;
+ switch (intent.getIntExtra("state", TelephonyManager.CALL_STATE_IDLE)) {
+ case TelephonyManager.CALL_STATE_RINGING:
+ mCallControlButton.setImageResource(R.drawable.ic_call_accept);
+ mCallControlButton.setVisibility(View.VISIBLE);
+ break;
+ case TelephonyManager.CALL_STATE_IDLE:
+ mCallControlButton.setVisibility(View.GONE);
+ break;
+ case TelephonyManager.CALL_STATE_OFFHOOK:
+ mCallControlButton.setImageResource(R.drawable.ic_call_end);
+ mCallControlButton.setVisibility(View.VISIBLE);
+ break;
+ }
+ mCallStatus = intent.getIntExtra("state", TelephonyManager.CALL_STATE_IDLE);
+ }
+ };
+
private SharedPreferences mPreferences;
public OverlayService() {
@@ -103,6 +130,8 @@
intentFilter.addAction(Constants.Broadcasts.BROADCAST_GAMING_MENU_CONTROL);
LocalBroadcastManager.getInstance(this).registerReceiver(mOMReceiver, intentFilter);
+ LocalBroadcastManager.getInstance(this).registerReceiver(mCallStatusReceiver, new IntentFilter(Constants.Broadcasts.BROADCAST_CALL_STATUS));
+
registerReceiver(mSysConfigChangedReceiver, new IntentFilter(Intent.ACTION_CONFIGURATION_CHANGED));
mPreferences = PreferenceManager.getDefaultSharedPreferences(this);
@@ -118,7 +147,7 @@
private void initView() {
mWindowManager = (WindowManager) getApplicationContext().getSystemService(Context.WINDOW_SERVICE);
initGamingMenu();
- initFloatingButton();
+ initFloatingLayout();
initDanmaku();
}
@@ -134,7 +163,7 @@
}
// 悬浮球位置调整
- if (mGamingFloatingButton != null && mGamingFBLayoutParams != null) {
+ if (mGamingFloatingLayout != null && mGamingFBLayoutParams != null) {
int defaultX = ((int) getResources().getDimension(R.dimen.game_button_size) - ScreenUtil.getScreenWidth()) / 2;
if (ScreenUtil.isPortrait()) {
mGamingFBLayoutParams.x = mPreferences.getInt(Constants.LocalConfigKeys.FLOATING_BUTTON_COORDINATE_VERTICAL_X, defaultX);
@@ -144,7 +173,7 @@
mGamingFBLayoutParams.y = mPreferences.getInt(Constants.LocalConfigKeys.FLOATING_BUTTON_COORDINATE_HORIZONTAL_Y, 10);
}
if (mWindowManager != null) {
- mWindowManager.updateViewLayout(mGamingFloatingButton, mGamingFBLayoutParams);
+ mWindowManager.updateViewLayout(mGamingFloatingLayout, mGamingFBLayoutParams);
}
}
@@ -190,16 +219,15 @@
}
}
- private void initFloatingButton() {
- if (mGamingFloatingButton == null && mWindowManager != null) {
- mGamingFloatingButton = LayoutInflater.from(this).inflate(R.layout.gaming_button_layout, null);
+ private void initFloatingLayout() {
+ if (mGamingFloatingLayout == null && mWindowManager != null) {
+ mGamingFloatingLayout = LayoutInflater.from(this).inflate(R.layout.gaming_button_layout, null);
mGamingFBLayoutParams = getBaseLayoutParams();
mGamingFBLayoutParams.width = WindowManager.LayoutParams.WRAP_CONTENT;
mGamingFBLayoutParams.height = WindowManager.LayoutParams.WRAP_CONTENT;
- mGamingFloatingButton.setOnClickListener(v -> showHideGamingMenu(0));
- mGamingFloatingButton.setOnTouchListener(new View.OnTouchListener() {
+ mGamingFloatingLayout.setOnTouchListener(new View.OnTouchListener() {
private int origX;
private int origY;
private int touchX;
@@ -221,7 +249,7 @@
mGamingFBLayoutParams.x = origX + x - touchX;
mGamingFBLayoutParams.y = origY + y - touchY;
if (mWindowManager != null) {
- mWindowManager.updateViewLayout(mGamingFloatingButton, mGamingFBLayoutParams);
+ mWindowManager.updateViewLayout(mGamingFloatingLayout, mGamingFBLayoutParams);
}
break;
case MotionEvent.ACTION_UP:
@@ -248,7 +276,17 @@
}
});
- mWindowManager.addView(mGamingFloatingButton, mGamingFBLayoutParams);
+ mWindowManager.addView(mGamingFloatingLayout, mGamingFBLayoutParams);
+ }
+
+ if (mGamingFloatingButton == null) {
+ mGamingFloatingButton = mGamingFloatingLayout.findViewById(R.id.floating_button);
+ mGamingFloatingButton.setOnClickListener(v -> showHideGamingMenu(0));
+ }
+
+ if (mCallControlButton == null) {
+ mCallControlButton = mGamingFloatingLayout.findViewById(R.id.call_control_button);
+ mCallControlButton.setOnClickListener(v -> callControl());
}
}
@@ -263,7 +301,7 @@
if (mGamingOverlayView.getVisibility() == View.VISIBLE && mode != 1) {
// hide
mGamingOverlayView.setVisibility(View.GONE);
- mGamingFloatingButton.setVisibility(View.VISIBLE);
+ mGamingFloatingLayout.setVisibility(View.VISIBLE);
} else if (mode != 2) {
// show
int gravity = 0;
@@ -278,7 +316,7 @@
gravity |= Gravity.TOP;
}
- mGamingFloatingButton.setVisibility(View.GONE);
+ mGamingFloatingLayout.setVisibility(View.GONE);
mGamingOverlayView.setGravity(gravity);
ViewGroup.LayoutParams gamingMenuLayoutParams = mGamingMenu.getLayoutParams();
if (ScreenUtil.isPortrait()) {
@@ -318,15 +356,22 @@
@Override
public void onDestroy() {
LocalBroadcastManager.getInstance(this).unregisterReceiver(mOMReceiver);
+ LocalBroadcastManager.getInstance(this).unregisterReceiver(mCallStatusReceiver);
unregisterReceiver(mSysConfigChangedReceiver);
if (mWindowManager != null) {
- if (mGamingFloatingButton != null) mWindowManager.removeViewImmediate(mGamingFloatingButton);
+ if (mGamingFloatingLayout != null) mWindowManager.removeViewImmediate(mGamingFloatingLayout);
if (mDanmakuContainer != null) mWindowManager.removeViewImmediate(mDanmakuContainer);
if (mGamingOverlayView != null) mWindowManager.removeViewImmediate(mGamingOverlayView);
}
super.onDestroy();
}
+ private void callControl() {
+ Intent intent = new Intent(Constants.Broadcasts.BROADCAST_CALL_CONTROL);
+ intent.putExtra("cmd", mCallStatus == TelephonyManager.CALL_STATE_OFFHOOK ? 1 : 2);
+ LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
+ }
+
private class OMReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
diff --git a/app/src/main/privapp_whitelist_org.exthmui.game.xml b/app/src/main/privapp_whitelist_org.exthmui.game.xml
index 8a06482..596e0f6 100644
--- a/app/src/main/privapp_whitelist_org.exthmui.game.xml
+++ b/app/src/main/privapp_whitelist_org.exthmui.game.xml
@@ -18,5 +18,6 @@
<privapp-permissions package="org.exthmui.game">
<permission name="android.permission.MEDIA_CONTENT_CONTROL"/>
<permission name="android.permission.MODIFY_PHONE_STATE"/>
+ <permission name="android.permission.ANSWER_PHONE_CALLS"/>
</privapp-permissions>
</permissions>
diff --git a/app/src/main/res/drawable/ic_call_accept.xml b/app/src/main/res/drawable/ic_call_accept.xml
new file mode 100644
index 0000000..db80ee9
--- /dev/null
+++ b/app/src/main/res/drawable/ic_call_accept.xml
@@ -0,0 +1,17 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="108dp"
+ android:height="108dp"
+ android:viewportWidth="108"
+ android:viewportHeight="108">
+ <path
+ android:fillColor="#00AA00"
+ android:pathData="M4,54 A50,50 0 1 0 4,53.99999"/>
+ <group android:scaleX="2.94408"
+ android:scaleY="2.94408"
+ android:translateX="18.67104"
+ android:translateY="18.67104">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M20.01,15.38c-1.23,0 -2.42,-0.2 -3.53,-0.56 -0.35,-0.12 -0.74,-0.03 -1.01,0.24l-1.57,1.97c-2.83,-1.35 -5.48,-3.9 -6.89,-6.83l1.95,-1.66c0.27,-0.28 0.35,-0.67 0.24,-1.02 -0.37,-1.11 -0.56,-2.3 -0.56,-3.53 0,-0.54 -0.45,-0.99 -0.99,-0.99H4.19C3.65,3 3,3.24 3,3.99 3,13.28 10.73,21 20.01,21c0.71,0 0.99,-0.63 0.99,-1.18v-3.45c0,-0.54 -0.45,-0.99 -0.99,-0.99z"/>
+ </group>
+</vector>
\ No newline at end of file
diff --git a/app/src/main/res/drawable/ic_call_end.xml b/app/src/main/res/drawable/ic_call_end.xml
new file mode 100644
index 0000000..2d878e0
--- /dev/null
+++ b/app/src/main/res/drawable/ic_call_end.xml
@@ -0,0 +1,17 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="108dp"
+ android:height="108dp"
+ android:viewportWidth="108"
+ android:viewportHeight="108">
+ <path
+ android:fillColor="#BB0000"
+ android:pathData="M4,54 A50,50 0 1 0 4,53.99999"/>
+ <group android:scaleX="2.94408"
+ android:scaleY="2.94408"
+ android:translateX="18.67104"
+ android:translateY="18.67104">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M12,9c-1.6,0 -3.15,0.25 -4.6,0.72v3.1c0,0.39 -0.23,0.74 -0.56,0.9 -0.98,0.49 -1.87,1.12 -2.66,1.85 -0.18,0.18 -0.43,0.28 -0.7,0.28 -0.28,0 -0.53,-0.11 -0.71,-0.29L0.29,13.08c-0.18,-0.17 -0.29,-0.42 -0.29,-0.7 0,-0.28 0.11,-0.53 0.29,-0.71C3.34,8.78 7.46,7 12,7s8.66,1.78 11.71,4.67c0.18,0.18 0.29,0.43 0.29,0.71 0,0.28 -0.11,0.53 -0.29,0.71l-2.48,2.48c-0.18,0.18 -0.43,0.29 -0.71,0.29 -0.27,0 -0.52,-0.11 -0.7,-0.28 -0.79,-0.74 -1.69,-1.36 -2.67,-1.85 -0.33,-0.16 -0.56,-0.5 -0.56,-0.9v-3.1C15.15,9.25 13.6,9 12,9z"/>
+ </group>
+</vector>
\ No newline at end of file
diff --git a/app/src/main/res/layout/gaming_button_layout.xml b/app/src/main/res/layout/gaming_button_layout.xml
index fc686a3..848585c 100644
--- a/app/src/main/res/layout/gaming_button_layout.xml
+++ b/app/src/main/res/layout/gaming_button_layout.xml
@@ -1,7 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="wrap_content" android:layout_height="wrap_content"
- android:background="@android:color/transparent">
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:background="@android:color/transparent"
+ android:padding="6dp">
+
<ImageView
android:id="@+id/floating_button"
android:layout_width="@dimen/game_button_size"
@@ -9,4 +12,17 @@
android:contentDescription="@null"
android:scaleType="fitCenter"
android:src="@drawable/ic_game_button" />
-</FrameLayout>
\ No newline at end of file
+
+ <Space
+ android:layout_width="6dp"
+ android:layout_height="wrap_content" />
+
+ <ImageView
+ android:id="@+id/call_control_button"
+ android:layout_width="@dimen/game_button_size"
+ android:layout_height="@dimen/game_button_size"
+ android:contentDescription="@null"
+ android:scaleType="fitCenter"
+ android:src="@drawable/ic_call_end"
+ android:visibility="gone" />
+</LinearLayout>
\ No newline at end of file