added incoming call showing on the external screen

This commit is contained in:
Talmid of Levi 2024-02-07 11:51:58 -05:00
parent 180c2b8cf6
commit bae2e134d3
21 changed files with 153 additions and 24 deletions

10
.idea/deploymentTargetDropDown.xml generated Normal file
View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="deploymentTargetDropDown">
<value>
<entry key="app">
<State />
</entry>
</value>
</component>
</project>

10
.idea/migrations.xml generated Normal file
View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectMigrations">
<option name="MigrateToGradleLocalJavaHome">
<set>
<option value="$PROJECT_DIR$" />
</set>
</option>
</component>
</project>

Binary file not shown.

View File

@ -4,6 +4,14 @@ plugins {
} }
android { android {
signingConfigs {
getByName("debug") {
storeFile = file("/home/talmid/Downloads/keystore/platform.keystore")
storePassword = "password"
keyAlias = "platform"
keyPassword = "password"
}
}
namespace = "net.mezimmah.catflipscreen" namespace = "net.mezimmah.catflipscreen"
compileSdk = 34 compileSdk = 34
@ -12,7 +20,7 @@ android {
minSdk = 30 minSdk = 30
targetSdk = 34 targetSdk = 34
versionCode = 1 versionCode = 1
versionName = "1.0" versionName = "1.1"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables { vectorDrawables {
@ -27,6 +35,7 @@ android {
getDefaultProguardFile("proguard-android-optimize.txt"), getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro" "proguard-rules.pro"
) )
signingConfig = signingConfigs.getByName("debug")
} }
} }
compileOptions { compileOptions {
@ -52,8 +61,8 @@ android {
dependencies { dependencies {
implementation("androidx.core:core-ktx:1.12.0") implementation("androidx.core:core-ktx:1.12.0")
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.6.2") implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.7.0")
implementation("androidx.activity:activity-compose:1.8.1") implementation("androidx.activity:activity-compose:1.8.2")
implementation(platform("androidx.compose:compose-bom:2023.03.00")) implementation(platform("androidx.compose:compose-bom:2023.03.00"))
implementation("androidx.compose.ui:ui") implementation("androidx.compose.ui:ui")
implementation("androidx.compose.ui:ui-graphics") implementation("androidx.compose.ui:ui-graphics")
@ -61,7 +70,7 @@ dependencies {
implementation("androidx.compose.material3:material3") implementation("androidx.compose.material3:material3")
implementation("androidx.appcompat:appcompat:1.6.1") implementation("androidx.appcompat:appcompat:1.6.1")
implementation("androidx.preference:preference-ktx:1.2.1") implementation("androidx.preference:preference-ktx:1.2.1")
implementation("com.google.android.material:material:1.10.0") implementation("com.google.android.material:material:1.11.0")
testImplementation("junit:junit:4.13.2") testImplementation("junit:junit:4.13.2")
androidTestImplementation("androidx.test.ext:junit:1.1.5") androidTestImplementation("androidx.test.ext:junit:1.1.5")
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1") androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")

Binary file not shown.

View File

@ -12,7 +12,7 @@
"filters": [], "filters": [],
"attributes": [], "attributes": [],
"versionCode": 1, "versionCode": 1,
"versionName": "1.0", "versionName": "1.1",
"outputFile": "app-release.apk" "outputFile": "app-release.apk"
} }
], ],

View File

@ -11,6 +11,9 @@
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/> <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WAKE_LOCK" /> <uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.READ_CALL_LOG"/>
<uses-permission android:name="android.permission.READ_CONTACTS"/>
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<application <application
android:name=".CatFlipScreenApplication" android:name=".CatFlipScreenApplication"
@ -30,6 +33,7 @@
android:exported="true"> android:exported="true">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" /> <action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.PHONE_STATE"/>
</intent-filter> </intent-filter>
</receiver> </receiver>
@ -44,12 +48,10 @@
android:name=".MainActivity" android:name=".MainActivity"
android:exported="true" android:exported="true"
android:launchMode="singleTop" android:launchMode="singleTop"
android:showOnLockScreen="true" android:showOnLockScreen="true"
android:theme="@style/Theme.AppCompat"> android:theme="@style/Theme.AppCompat">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" /> <category android:name="android.intent.category.LAUNCHER" />
</intent-filter> </intent-filter>
</activity> </activity>

View File

@ -28,6 +28,7 @@ class CatFlipScreenApplication : Application() {
const val CHANNEL_NAME = "Auto Start Service Channel" const val CHANNEL_NAME = "Auto Start Service Channel"
const val BROADCAST_BATTERY_CHANGED = "BROADCAST_BATTERY_CHANGED" const val BROADCAST_BATTERY_CHANGED = "BROADCAST_BATTERY_CHANGED"
const val BROADCAST_AUDIO_MODE_CHANGED = "BROADCAST_AUDIO_MODE_CHANGED" const val BROADCAST_AUDIO_MODE_CHANGED = "BROADCAST_AUDIO_MODE_CHANGED"
const val BROADCAST_TELEPHONY_ACTION = "BROADCAST_TELEPHONY_ACTION"
} }
} }

View File

@ -18,11 +18,11 @@ import android.util.Log
import androidx.core.app.NotificationCompat import androidx.core.app.NotificationCompat
import androidx.localbroadcastmanager.content.LocalBroadcastManager import androidx.localbroadcastmanager.content.LocalBroadcastManager
class FlipScreenService : Service() { class FlipScreenService : Service() {
override fun onBind(intent: Intent): IBinder? { override fun onBind(intent: Intent): IBinder? {
TODO("Return the communication channel to the service.") TODO("Return the communication channel to the service.")
@Suppress("UNREACHABLE_CODE")
return null return null
} }
@ -67,9 +67,9 @@ class FlipScreenService : Service() {
0, notificationIntent, PendingIntent.FLAG_IMMUTABLE 0, notificationIntent, PendingIntent.FLAG_IMMUTABLE
) )
val notification: Notification = NotificationCompat.Builder(this, CatFlipScreenApplication.CHANNEL_ID) val notification: Notification = NotificationCompat.Builder(this, CatFlipScreenApplication.CHANNEL_ID)
.setContentTitle("Auto Start Service") .setContentTitle("External Screen")
.setContentText(input) .setContentText(input)
.setSmallIcon(android.R.drawable.ic_dialog_alert) .setSmallIcon(R.drawable.icons8_phone_50)
.setContentIntent(pendingIntent) .setContentIntent(pendingIntent)
.build() .build()
val mNotificationManager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager val mNotificationManager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
@ -109,8 +109,7 @@ class FlipScreenService : Service() {
} catch (e: Exception) { } catch (e: Exception) {
Log.w( Log.w(
"StatusBar", "StatusBar",
"Couldn't show presentation! Display was removed in the meantime.", "Couldn't show presentation! Display was removed in the meantime.", e
e
) )
} }
} }

View File

@ -2,8 +2,11 @@ package net.mezimmah.catflipscreen
import android.content.Intent import android.content.Intent
import android.content.SharedPreferences import android.content.SharedPreferences
import android.content.pm.PackageManager
import android.os.Bundle import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.preference.PreferenceFragmentCompat import androidx.preference.PreferenceFragmentCompat
@ -21,7 +24,27 @@ class MainActivity : AppCompatActivity() {
startForegroundService(Intent(this, FlipScreenService::class.java)) startForegroundService(Intent(this, FlipScreenService::class.java))
} }
override fun onResume() {
super.onResume()
askForPermission(android.Manifest.permission.READ_PHONE_STATE)
askForPermission(android.Manifest.permission.READ_CALL_LOG)
}
private fun askForPermission(permission: String) {
@Suppress("DEPRECATED_IDENTITY_EQUALS")
if (ContextCompat.checkSelfPermission(this@MainActivity,
permission) !==
PackageManager.PERMISSION_GRANTED) {
if (ActivityCompat.shouldShowRequestPermissionRationale(this@MainActivity,
permission)) {
ActivityCompat.requestPermissions(this@MainActivity,
arrayOf(permission), 1)
} else {
ActivityCompat.requestPermissions(this@MainActivity,
arrayOf(permission), 1)
}
}
}
class SettingsFragment : PreferenceFragmentCompat(), SharedPreferences.OnSharedPreferenceChangeListener { class SettingsFragment : PreferenceFragmentCompat(), SharedPreferences.OnSharedPreferenceChangeListener {
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
setPreferencesFromResource(R.xml.root_preferences, rootKey) setPreferencesFromResource(R.xml.root_preferences, rootKey)
@ -36,7 +59,5 @@ class MainActivity : AppCompatActivity() {
preferenceScreen.sharedPreferences preferenceScreen.sharedPreferences
?.registerOnSharedPreferenceChangeListener(this) ?.registerOnSharedPreferenceChangeListener(this)
} }
} }
} }

View File

@ -4,14 +4,32 @@ import android.content.BroadcastReceiver
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.Intent.ACTION_BOOT_COMPLETED import android.content.Intent.ACTION_BOOT_COMPLETED
import android.telephony.TelephonyManager
import android.util.Log import android.util.Log
import androidx.localbroadcastmanager.content.LocalBroadcastManager
class MyReceiver : BroadcastReceiver() { class MyReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) { override fun onReceive(context: Context, intent: Intent) {
when (intent.action) { if (intent.action.equals(ACTION_BOOT_COMPLETED)) {
ACTION_BOOT_COMPLETED -> startFlipScreenService(context) startFlipScreenService(context)
return
}
val state = intent.getStringExtra(TelephonyManager.EXTRA_STATE)
when (state) {
TelephonyManager.EXTRA_STATE_RINGING -> {
val i = Intent(CatFlipScreenApplication.BROADCAST_TELEPHONY_ACTION)
@Suppress("DEPRECATION")
i.putExtra("number", intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER))
LocalBroadcastManager.getInstance(context)
.sendBroadcast(i)
}
TelephonyManager.EXTRA_STATE_IDLE -> {
val i = Intent(CatFlipScreenApplication.BROADCAST_TELEPHONY_ACTION)
i.putExtra("number", "")
LocalBroadcastManager.getInstance(context)
.sendBroadcast(i)
}
} }
} }

View File

@ -3,6 +3,8 @@ package net.mezimmah.catflipscreen
import android.app.Presentation import android.app.Presentation
import android.content.BroadcastReceiver import android.content.BroadcastReceiver
import android.content.Context import android.content.Context
import android.content.Context.AUDIO_SERVICE
import android.content.Context.CONNECTIVITY_SERVICE
import android.content.Intent import android.content.Intent
import android.content.IntentFilter import android.content.IntentFilter
import android.media.AudioManager import android.media.AudioManager
@ -15,6 +17,7 @@ import android.os.Bundle
import android.view.Display import android.view.Display
import android.view.View import android.view.View
import android.widget.ImageView import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.TextView import android.widget.TextView
import androidx.localbroadcastmanager.content.LocalBroadcastManager import androidx.localbroadcastmanager.content.LocalBroadcastManager
@ -29,6 +32,9 @@ class PresentationScreen(outerContext: Context?, display: Display?) :
private var networkIconView: ImageView? = null private var networkIconView: ImageView? = null
private var wifiIconView: ImageView? = null private var wifiIconView: ImageView? = null
private var audioLevelIconView: ImageView? = null private var audioLevelIconView: ImageView? = null
private var missedCallsIconView: ImageView? = null
private var telephonyCalling: TextView? = null
private var telephonyLayout: LinearLayout? = null
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
@ -52,12 +58,15 @@ class PresentationScreen(outerContext: Context?, display: Display?) :
networkIconView = findViewById(R.id.screen_status_bar_network_signal) networkIconView = findViewById(R.id.screen_status_bar_network_signal)
wifiIconView = findViewById(R.id.screen_status_bar_wifi_signal) wifiIconView = findViewById(R.id.screen_status_bar_wifi_signal)
audioLevelIconView = findViewById(R.id.screen_status_bar_audio_level) audioLevelIconView = findViewById(R.id.screen_status_bar_audio_level)
telephonyCalling = findViewById(R.id.screen_telephony_number)
telephonyLayout = findViewById(R.id.screen_telephony_calling_layout)
missedCallsIconView = findViewById(R.id.screen_status_bar_missed_calls)
} }
private fun getSystemServices() { private fun getSystemServices() {
am = context.getSystemService(Context.AUDIO_SERVICE) as AudioManager? am = context.getSystemService(AUDIO_SERVICE) as AudioManager?
connectivityManager = connectivityManager =
context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager context.getSystemService(CONNECTIVITY_SERVICE) as ConnectivityManager
} }
private fun registerReceivers() { private fun registerReceivers() {
@ -71,6 +80,9 @@ class PresentationScreen(outerContext: Context?, display: Display?) :
CatFlipScreenApplication.BROADCAST_AUDIO_MODE_CHANGED -> { CatFlipScreenApplication.BROADCAST_AUDIO_MODE_CHANGED -> {
updateAudioMode() updateAudioMode()
} }
CatFlipScreenApplication.BROADCAST_TELEPHONY_ACTION -> {
updateCallStatus(intent)
}
} }
} }
} }
@ -78,6 +90,8 @@ class PresentationScreen(outerContext: Context?, display: Display?) :
.registerReceiver(broadCastReceiver, IntentFilter(CatFlipScreenApplication.BROADCAST_BATTERY_CHANGED)) .registerReceiver(broadCastReceiver, IntentFilter(CatFlipScreenApplication.BROADCAST_BATTERY_CHANGED))
LocalBroadcastManager.getInstance(context) LocalBroadcastManager.getInstance(context)
.registerReceiver(broadCastReceiver, IntentFilter(CatFlipScreenApplication.BROADCAST_AUDIO_MODE_CHANGED)) .registerReceiver(broadCastReceiver, IntentFilter(CatFlipScreenApplication.BROADCAST_AUDIO_MODE_CHANGED))
LocalBroadcastManager.getInstance(context)
.registerReceiver(broadCastReceiver, IntentFilter(CatFlipScreenApplication.BROADCAST_TELEPHONY_ACTION))
// Register receiver for the network updates // Register receiver for the network updates
val networkRequest = NetworkRequest.Builder() val networkRequest = NetworkRequest.Builder()
@ -170,4 +184,10 @@ class PresentationScreen(outerContext: Context?, display: Display?) :
} }
} }
} }
private fun updateCallStatus(intent: Intent) {
val number = intent.getStringExtra("number")
telephonyCalling?.text = number
telephonyLayout?.visibility = if (number.isNullOrBlank()) View.INVISIBLE else View.VISIBLE
}
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 741 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 920 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 964 B

View File

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="96dp" android:layout_width="96dp"
android:layout_height="96dp" android:layout_height="96dp"
android:background="@color/black" android:background="@color/black"
@ -61,6 +62,15 @@
android:layout_marginRight="-3dp" android:layout_marginRight="-3dp"
android:paddingTop="3dp"/> android:paddingTop="3dp"/>
<ImageView
android:contentDescription="@string/audio_level_icon"
android:id="@+id/screen_status_bar_missed_calls"
android:src="@drawable/icons8_missed_call_64"
android:layout_width="15dp"
android:layout_height="12dp"
android:visibility="invisible"
android:layout_marginRight="-3dp"
android:paddingTop="3dp"/>
</LinearLayout> </LinearLayout>
@ -80,4 +90,31 @@
android:textColor="@color/white" android:textColor="@color/white"
android:textSize="10sp" /> android:textSize="10sp" />
<LinearLayout
android:id="@+id/screen_telephony_calling_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:layout_marginTop="5dp"
android:visibility="invisible"
android:orientation="horizontal"
tools:ignore="UseCompoundDrawables">
<ImageView
android:layout_width="10dp"
android:layout_height="10dp"
android:layout_gravity="center"
android:contentDescription="@string/app_name"
android:src="@drawable/icons8_incoming_call_50" />
<TextView
android:id="@+id/screen_telephony_number"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAlignment="textStart"
android:textColor="@color/white"
android:textSize="10sp" />
</LinearLayout>
</LinearLayout> </LinearLayout>

View File

@ -5,5 +5,6 @@
<FrameLayout <FrameLayout
android:id="@+id/settings" android:id="@+id/settings"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" /> android:layout_height="match_parent" >
</FrameLayout>
</LinearLayout> </LinearLayout>

View File

@ -21,6 +21,7 @@
<string name="enable_external_display">Turn on your external screen, this will restart your phone</string> <string name="enable_external_display">Turn on your external screen, this will restart your phone</string>
<string name="status_bar_percentage">%</string> <string name="status_bar_percentage">%</string>
<string name="audio_level_icon">Audio Level Icon</string> <string name="audio_level_icon">Audio Level Icon</string>
<string name="missed_calls_icon">Missed Calls Icon</string>
<string name="wifi_signal_icon">Wifi Signal Icon</string> <string name="wifi_signal_icon">Wifi Signal Icon</string>
<string name="network_signal_icon">Network Signal Icon</string> <string name="network_signal_icon">Network Signal Icon</string>
<string name="battery_status_icon">Battery Status Icon</string> <string name="battery_status_icon">Battery Status Icon</string>

View File

@ -21,7 +21,7 @@
<Preference <Preference
app:selectable="false" app:selectable="false"
app:enabled="true" app:enabled="true"
app:title="Cat Flip Screen" app:title=""
app:summary="This app makes the external screen to show the clock, batter, sound profile and connectivity status." /> app:summary="In order for this app to work properly please enable all permissions in the app settings." />
</PreferenceScreen> </PreferenceScreen>

View File

@ -1,5 +1,5 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules. // Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins { plugins {
id("com.android.application") version "8.1.4" apply false id("com.android.application") version "8.2.2" apply false
id("org.jetbrains.kotlin.android") version "1.8.10" apply false id("org.jetbrains.kotlin.android") version "1.8.10" apply false
} }

View File

@ -1,6 +1,6 @@
#Wed Nov 22 10:46:25 EST 2023 #Wed Nov 22 10:46:25 EST 2023
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists