mirror of
				https://github.com/oplus-giulia-dev/android_hardware_oplus
				synced 2025-11-04 05:45:34 +08:00 
			
		
		
		
	Introduce OplusPen
Change-Id: Icfc9d2d8172aa01bf1c71a5a23a8e6387660a746
This commit is contained in:
		
							
								
								
									
										29
									
								
								Pen/Android.bp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								Pen/Android.bp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,29 @@
 | 
			
		||||
//
 | 
			
		||||
// SPDX-FileCopyrightText: 2025 The LineageOS Project
 | 
			
		||||
// SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
android_app {
 | 
			
		||||
    name: "OplusPen",
 | 
			
		||||
 | 
			
		||||
    srcs: ["src/**/*.kt"],
 | 
			
		||||
 | 
			
		||||
    certificate: "platform",
 | 
			
		||||
    platform_apis: true,
 | 
			
		||||
    system_ext_specific: true,
 | 
			
		||||
 | 
			
		||||
    optimize: {
 | 
			
		||||
        proguard_flags_files: ["proguard.flags"],
 | 
			
		||||
    },
 | 
			
		||||
    required: [
 | 
			
		||||
        "default-permissions_org.lineageos.pen",
 | 
			
		||||
    ],
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
prebuilt_etc {
 | 
			
		||||
    name: "default-permissions_org.lineageos.pen",
 | 
			
		||||
    system_ext_specific: true,
 | 
			
		||||
    src: "default-permissions_org.lineageos.pen.xml",
 | 
			
		||||
    sub_dir: "default-permissions",
 | 
			
		||||
    filename_from_src: true,
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										31
									
								
								Pen/AndroidManifest.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								Pen/AndroidManifest.xml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,31 @@
 | 
			
		||||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<!--
 | 
			
		||||
    SPDX-FileCopyrightText: 2025 The LineageOS Project
 | 
			
		||||
    SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
-->
 | 
			
		||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
          package="org.lineageos.pen">
 | 
			
		||||
 | 
			
		||||
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
 | 
			
		||||
    <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
 | 
			
		||||
    <uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
 | 
			
		||||
    <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
 | 
			
		||||
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
 | 
			
		||||
 | 
			
		||||
    <application
 | 
			
		||||
        android:label="@string/app_name"
 | 
			
		||||
        android:persistent="true"
 | 
			
		||||
        android:usesNonSdkApi="true">
 | 
			
		||||
        <receiver
 | 
			
		||||
            android:exported="true"
 | 
			
		||||
            android:name=".BootCompletedReceiver">
 | 
			
		||||
            <intent-filter>
 | 
			
		||||
                <action android:name="android.intent.action.BOOT_COMPLETED" />
 | 
			
		||||
                <category android:name="android.intent.category.DEFAULT" />
 | 
			
		||||
            </intent-filter>
 | 
			
		||||
        </receiver>
 | 
			
		||||
        <service
 | 
			
		||||
            android:exported="false"
 | 
			
		||||
            android:name=".PenService" />
 | 
			
		||||
    </application>
 | 
			
		||||
</manifest>
 | 
			
		||||
							
								
								
									
										13
									
								
								Pen/default-permissions_org.lineageos.pen.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								Pen/default-permissions_org.lineageos.pen.xml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,13 @@
 | 
			
		||||
<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
 | 
			
		||||
<!--
 | 
			
		||||
    SPDX-FileCopyrightText: 2025 The LineageOS Project
 | 
			
		||||
    SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
-->
 | 
			
		||||
<exceptions>
 | 
			
		||||
    <exception package="org.lineageos.pen">
 | 
			
		||||
        <permission name="android.permission.ACCESS_FINE_LOCATION" fixed="false" />
 | 
			
		||||
        <permission name="android.permission.BLUETOOTH_CONNECT" fixed="false" />
 | 
			
		||||
        <permission name="android.permission.BLUETOOTH_SCAN" fixed="false" />
 | 
			
		||||
        <permission name="android.permission.POST_NOTIFICATIONS" fixed="false" />
 | 
			
		||||
    </exception>
 | 
			
		||||
</exceptions>
 | 
			
		||||
							
								
								
									
										3
									
								
								Pen/proguard.flags
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								Pen/proguard.flags
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,3 @@
 | 
			
		||||
-keep class org.lineageos.pen.* {
 | 
			
		||||
  *;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										15
									
								
								Pen/res/drawable/ic_stylus.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								Pen/res/drawable/ic_stylus.xml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,15 @@
 | 
			
		||||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<!--
 | 
			
		||||
     SPDX-FileCopyrightText: Material Design Authors / Google LLC
 | 
			
		||||
     SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
-->
 | 
			
		||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
    android:width="24dp"
 | 
			
		||||
    android:height="24dp"
 | 
			
		||||
    android:tint="#000000"
 | 
			
		||||
    android:viewportWidth="960"
 | 
			
		||||
    android:viewportHeight="960">
 | 
			
		||||
    <path
 | 
			
		||||
        android:fillColor="@android:color/white"
 | 
			
		||||
        android:pathData="M167,840Q146,845 130.5,829.5Q115,814 120,793L160,602L358,800L167,840ZM358,800L160,602L618,144Q641,121 675,121Q709,121 732,144L816,228Q839,251 839,285Q839,319 816,342L358,800ZM675,200L261,614L346,699L760,285Q760,285 760,285Q760,285 760,285L675,200Q675,200 675,200Q675,200 675,200Z" />
 | 
			
		||||
</vector>
 | 
			
		||||
							
								
								
									
										10
									
								
								Pen/res/values/strings.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								Pen/res/values/strings.xml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,10 @@
 | 
			
		||||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<!--
 | 
			
		||||
    SPDX-FileCopyrightText: 2025 The LineageOS Project
 | 
			
		||||
    SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
-->
 | 
			
		||||
<resources>
 | 
			
		||||
    <string name="app_name" translatable="false">OplusPen</string>
 | 
			
		||||
    <string name="pen_attached">Pen attached</string>
 | 
			
		||||
    <string name="tap_to_connect">Tap to connect</string>
 | 
			
		||||
</resources>
 | 
			
		||||
							
								
								
									
										22
									
								
								Pen/src/org/lineageos/pen/BootCompletedReceiver.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								Pen/src/org/lineageos/pen/BootCompletedReceiver.kt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,22 @@
 | 
			
		||||
/*
 | 
			
		||||
 * SPDX-FileCopyrightText: 2025 The LineageOS Project
 | 
			
		||||
 * SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
package org.lineageos.pen
 | 
			
		||||
 | 
			
		||||
import android.content.BroadcastReceiver
 | 
			
		||||
import android.content.Context
 | 
			
		||||
import android.content.Intent
 | 
			
		||||
import android.util.Log
 | 
			
		||||
 | 
			
		||||
class BootCompletedReceiver : BroadcastReceiver() {
 | 
			
		||||
    override fun onReceive(context: Context, intent: Intent) {
 | 
			
		||||
        Log.d(TAG, "Received boot completed intent")
 | 
			
		||||
        context.startService(Intent(context, PenService::class.java))
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    companion object {
 | 
			
		||||
        private const val TAG = "OplusPenBootReceiver"
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										145
									
								
								Pen/src/org/lineageos/pen/PenService.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										145
									
								
								Pen/src/org/lineageos/pen/PenService.kt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,145 @@
 | 
			
		||||
/*
 | 
			
		||||
 * SPDX-FileCopyrightText: 2025 The LineageOS Project
 | 
			
		||||
 * SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
package org.lineageos.pen
 | 
			
		||||
 | 
			
		||||
import android.app.Notification
 | 
			
		||||
import android.app.NotificationChannel
 | 
			
		||||
import android.app.NotificationManager
 | 
			
		||||
import android.app.PendingIntent
 | 
			
		||||
import android.app.Service
 | 
			
		||||
import android.bluetooth.BluetoothManager
 | 
			
		||||
import android.bluetooth.le.ScanCallback
 | 
			
		||||
import android.bluetooth.le.ScanFilter
 | 
			
		||||
import android.bluetooth.le.ScanResult
 | 
			
		||||
import android.bluetooth.le.ScanSettings
 | 
			
		||||
import android.content.Context
 | 
			
		||||
import android.content.Intent
 | 
			
		||||
import android.os.IBinder
 | 
			
		||||
import android.os.UEventObserver
 | 
			
		||||
import android.util.Log
 | 
			
		||||
 | 
			
		||||
class PenService : Service() {
 | 
			
		||||
    private val bluetoothManager by lazy { getSystemService(BluetoothManager::class.java) }
 | 
			
		||||
    private val notificationManager by lazy { getSystemService(NotificationManager::class.java) }
 | 
			
		||||
 | 
			
		||||
    private val observer = object : UEventObserver() {
 | 
			
		||||
        private val lock = Any()
 | 
			
		||||
 | 
			
		||||
        override fun onUEvent(event: UEvent) {
 | 
			
		||||
            synchronized(lock) {
 | 
			
		||||
                val pencilStatus = event.get("pencil_status") ?: return
 | 
			
		||||
                val pencilAddr = event.get("pencil_addr")?.chunked(2)?.joinToString(":") {
 | 
			
		||||
                    it.uppercase()
 | 
			
		||||
                } ?: return
 | 
			
		||||
 | 
			
		||||
                when (pencilStatus) {
 | 
			
		||||
                    "0" -> notificationManager.cancel(NOTIFICATION_ID)
 | 
			
		||||
                    "1" -> postNotification(pencilAddr)
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
 | 
			
		||||
        intent?.getStringExtra(EXTRA_PENCIL_ADDR)?.let {
 | 
			
		||||
            bondBtDevice(it)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return START_STICKY
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onBind(intent: Intent?): IBinder? = null
 | 
			
		||||
 | 
			
		||||
    override fun onCreate() {
 | 
			
		||||
        super.onCreate()
 | 
			
		||||
 | 
			
		||||
        observer.startObserving("DEVPATH=/devices/virtual/oplus_wireless/pencil")
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onDestroy() {
 | 
			
		||||
        super.onDestroy()
 | 
			
		||||
 | 
			
		||||
        observer.stopObserving()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun bondBtDevice(pencilAddr: String) {
 | 
			
		||||
        val adapter = bluetoothManager.adapter
 | 
			
		||||
        @Suppress("DEPRECATION") adapter.enable()
 | 
			
		||||
 | 
			
		||||
        val scanner = adapter.bluetoothLeScanner
 | 
			
		||||
        scanner.startScan(
 | 
			
		||||
            listOf(ScanFilter.Builder().setDeviceAddress(pencilAddr).build()),
 | 
			
		||||
            ScanSettings.Builder()
 | 
			
		||||
                .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
 | 
			
		||||
                .setReportDelay(0L)
 | 
			
		||||
                .build(),
 | 
			
		||||
            object : ScanCallback() {
 | 
			
		||||
                override fun onScanResult(callbackType: Int, result: ScanResult) {
 | 
			
		||||
                    super.onScanResult(callbackType, result)
 | 
			
		||||
                    scanner.stopScan(this)
 | 
			
		||||
 | 
			
		||||
                    result.device.createBond()
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                override fun onBatchScanResults(results: MutableList<ScanResult>) {
 | 
			
		||||
                    super.onBatchScanResults(results)
 | 
			
		||||
                    scanner.stopScan(this)
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                override fun onScanFailed(errorCode: Int) {
 | 
			
		||||
                    super.onScanFailed(errorCode)
 | 
			
		||||
                    scanner.stopScan(this)
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun postNotification(pencilAddr: String) {
 | 
			
		||||
        val adapter = bluetoothManager.adapter
 | 
			
		||||
 | 
			
		||||
        if (adapter.bondedDevices.contains(adapter.getRemoteDevice(pencilAddr))) {
 | 
			
		||||
            Log.e(TAG, "$pencilAddr already bonded, bailing out")
 | 
			
		||||
            return
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (notificationManager.getNotificationChannel(NOTIFICATION_CHANNEL_ID) == null) {
 | 
			
		||||
            notificationManager.createNotificationChannel(
 | 
			
		||||
                NotificationChannel(
 | 
			
		||||
                    NOTIFICATION_CHANNEL_ID,
 | 
			
		||||
                    NOTIFICATION_CHANNEL_ID,
 | 
			
		||||
                    NotificationManager.IMPORTANCE_HIGH
 | 
			
		||||
                )
 | 
			
		||||
            )
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        val contentIntent = PendingIntent.getService(
 | 
			
		||||
            this,
 | 
			
		||||
            0,
 | 
			
		||||
            Intent(this, PenService::class.java).apply {
 | 
			
		||||
                putExtra(EXTRA_PENCIL_ADDR, pencilAddr)
 | 
			
		||||
            },
 | 
			
		||||
            PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        val notification = Notification.Builder(this, NOTIFICATION_CHANNEL_ID)
 | 
			
		||||
            .setSmallIcon(R.drawable.ic_stylus)
 | 
			
		||||
            .setContentTitle(getString(R.string.pen_attached))
 | 
			
		||||
            .setContentText(getString(R.string.tap_to_connect))
 | 
			
		||||
            .setContentIntent(contentIntent)
 | 
			
		||||
            .setAutoCancel(true)
 | 
			
		||||
            .build()
 | 
			
		||||
        notificationManager.notify(NOTIFICATION_ID, notification)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    companion object {
 | 
			
		||||
        private const val TAG = "OplusPenService"
 | 
			
		||||
 | 
			
		||||
        private const val EXTRA_PENCIL_ADDR = "pencil_addr"
 | 
			
		||||
 | 
			
		||||
        private const val NOTIFICATION_CHANNEL_ID = "OplusPen"
 | 
			
		||||
        private const val NOTIFICATION_ID = 1000
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										8
									
								
								sepolicy/qti/private/pen_app.te
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								sepolicy/qti/private/pen_app.te
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,8 @@
 | 
			
		||||
type pen_app, domain, coredomain;
 | 
			
		||||
 | 
			
		||||
app_domain(pen_app)
 | 
			
		||||
bluetooth_domain(pen_app)
 | 
			
		||||
 | 
			
		||||
allow pen_app self:netlink_kobject_uevent_socket { create read setopt bind };
 | 
			
		||||
 | 
			
		||||
allow pen_app app_api_service:service_manager find;
 | 
			
		||||
							
								
								
									
										1
									
								
								sepolicy/qti/private/seapp_contexts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								sepolicy/qti/private/seapp_contexts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
user=_app seinfo=platform name=org.lineageos.pen domain=pen_app type=app_data_file levelFrom=user
 | 
			
		||||
		Reference in New Issue
	
	Block a user