Android原生副屏功能API,不需要集成SDK。

具体调用流程如下

-副屏申请权限

Androidmanifest.xml中增加如下代码:

<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />

== 简单功能示例 ==

效果图:

主屏:

Android 主屏副屏亮度 安卓副屏_ide

 副屏初始页面:

Android 主屏副屏亮度 安卓副屏_android studio_02

 副屏接收到主屏信息页面:

Android 主屏副屏亮度 安卓副屏_包名_03

代码如下:

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调用副屏,需要设置权限,图示如下

Android 主屏副屏亮度 安卓副屏_android studio_04

 

Android 主屏副屏亮度 安卓副屏_android_05

这里跳转设置页开启权限需要与用户交互,并且处理用户点击了”前往设置”按钮,但是没有开启开关又返回的情况,进行拦截,避免发生后续的崩溃或者是副屏显示异常的情况。

代码中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场景。这里只是做了最简单的展示,如果需要实际代码,可以参考餐饮零售会员的实际业务代码。