Android原生副屏功能API,不需要集成SDK。
具体调用流程如下
-副屏申请权限
Androidmanifest.xml中增加如下代码:
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
== 简单功能示例 ==
效果图:
主屏:
副屏初始页面:
副屏接收到主屏信息页面:
代码如下:
1.定义双屏Service,并在manifest文件中声明
public class DualScreenService extends Service {
public static final String SUB_ACTIVITY_TEST_UPDATE_CONTENT = "sub_activity_test_update_content";
// 获取设备上的屏幕
DisplayManager mDisplayManager;// 屏幕管理器
Display[] displays;// 屏幕数组
SubPresentation subPresentation; // (继承Presentation)
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
// 双屏异显
mDisplayManager = (DisplayManager) this.getSystemService(Context.DISPLAY_SERVICE);
displays = mDisplayManager.getDisplays();
registerRecevicer();
}
private void registerRecevicer() {
IntentFilter filter = new IntentFilter();
filter.addAction(SUB_ACTIVITY_TEST_UPDATE_CONTENT);
registerReceiver(receiver, filter);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
showView();
return super.onStartCommand(intent, flags, startId);
}
@SuppressLint("NewApi")
private void showView() {
if (displays.length < 2) {
Toast.makeText(getApplicationContext(), "开启副屏失败", Toast.LENGTH_SHORT).show();
return;
}
subPresentation = new SubPresentation(getApplicationContext(), displays[1]);// displays[1]是副屏
subPresentation.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
subPresentation.setCancelable(false);
subPresentation.show();
}
BroadcastReceiver receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
switch (action) {
case SUB_ACTIVITY_TEST_UPDATE_CONTENT:
subPresentation.updateContent(intent.getStringExtra("content"));
break;
default:
break;
}
}
};
}
<service
android:name=".DualScreenService"
android:exported="false" />
2.自定义副屏演示类
public class SubPresentation extends Presentation {
private ActivitySubScreenBinding binding;
public SubPresentation(Context mContext, Display display) {
super(mContext, display);
binding = ActivitySubScreenBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
public void updateContent(String content) {
binding.tvContent.setText("接收到:"+content);
}
}
说明:以上两个类是副屏功能最基础的两个类,service中主要是声明副屏服务的创建,创建并接收系统广播,处理主副屏之间的信息传递。SubPresentation 可以理解成副屏页面,有点Activity的概念,在其中主要是处理副屏UI上面的变化。
按照示例图,我们只做了主屏上点击按钮,发送”你好“到副屏,并显示出来。
那么我们声明了一个SUB_ACTIVITY_TEST_UPDATE_CONTENT指令名称,也就是只要广播中发现了这条指令,就调用subPresentation的updateContent方法,进而更改binding.tvContent的文本属性
MainActivity代码
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
checkDualScreenPermission();
Button btn_send = findViewById(R.id.btn_send);
btn_send.setOnClickListener(view -> {
Intent intent = new Intent();
intent.setAction(DualScreenService.SUB_ACTIVITY_TEST_UPDATE_CONTENT);
intent.putExtra("content", "你好!");
sendBroadcast(intent);
});
}
public void checkDualScreenPermission() {
if (Build.VERSION.SDK_INT >= 23) {
if (!Settings.canDrawOverlays(MainActivity.this)) {
new CommonDialog.Builder(this).setTitle("提示")
.setContent("副屏功能需要开启相关权限")
.setEnsureStr("前往设置")
.setCancelStr("退出应用")
.setEnsureClick(v1 -> {
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
Uri.parse("package:" + getPackageName()));
startActivityForResult(intent, 10);
})
.setCancelClick(v -> {
finish();
})
.show();
} else {
Intent service = new Intent();
service.setPackage(this.getPackageName());// 这里你需要设置你应用的包名
service.setClass(this, DualScreenService.class);
this.startService(service);
}
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == 10) {
if (Build.VERSION.SDK_INT >= 23) {
if (!Settings.canDrawOverlays(this)) {
// SYSTEM_ALERT_WINDOW permission not granted...
new CommonDialog.Builder(this).setTitle("提示")
.setContent("权限被拒绝或未开启")
.setEnsureStr("前往设置")
.setCancelStr("退出应用")
.setEnsureClick(v1 -> {
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
Uri.parse("package:" + getPackageName()));
startActivityForResult(intent, 10);
})
.setCancelClick(v -> {
finish();
})
.show();
} else {
Intent service = new Intent();
service.setPackage(this.getPackageName());// 这里你需要设置你应用的包名
service.setClass(this, DualScreenService.class);
this.startService(service);
}
}
}
}
@Override
protected void onDestroy() {
super.onDestroy();
Intent service = new Intent();
service.setPackage(getPackageName());// 这里你需要设置你应用的包名
service.setClass(MainActivity.this, DualScreenService.class);
stopService(service);
}
}
说明:
1.Android调用副屏,需要设置权限,图示如下
这里跳转设置页开启权限需要与用户交互,并且处理用户点击了”前往设置”按钮,但是没有开启开关又返回的情况,进行拦截,避免发生后续的崩溃或者是副屏显示异常的情况。
代码中checkDualScreenPermission()和onActivityResult()处理了该逻辑
2.具体的调用副屏的代码
Intent intent = new Intent();
intent.setAction(DualScreenService.SUB_ACTIVITY_TEST_UPDATE_CONTENT);
intent.putExtra("content", "你好!");
sendBroadcast(intent);
3.为了避免资源浪费,当app退出时,需要注销service
@Override
protected void onDestroy() {
super.onDestroy();
Intent service = new Intent();
service.setPackage(getPackageName());// 这里你需要设置你应用的包名
service.setClass(MainActivity.this, DualScreenService.class);
stopService(service);
}
写在后面,除了String文本,还可以通过intent传递所有支持的数据类型或者是序列化的对象数据,以实现业务中需要的各种UI场景。这里只是做了最简单的展示,如果需要实际代码,可以参考餐饮零售会员的实际业务代码。