Search code examples
androidkotlin

Edge lighting notification in kotlin


I'm trying to program an app that will use the edge lighting notification as shown in the picture. However, I have no idea what to use to handle that.

I have tried using canvas but that's not what I want since its limited to the app itself.


Solution

  • How to Create a Transparent, Gradient Border Around the Screen in an Android App

    For a solution that completely covers the screen regardless of the state/size of the app, you have several options. Here are two effective methods:

    Method 1: Using a Second Activity

    This method involves creating a second activity that displays a transparent gradient border.

    Pros:

    • Relatively easy to implement.

    Cons:

    • Could interfere with the UI of the main activity.
    • Requires a specific theme.

    Step-by-Step Implementation

    1. Define a Custom Theme for Full-Screen, Transparent Activity

    Create a custom theme in res/values/styles.xml that makes the activity full-screen and transparent.

    res/values/styles.xml:

    <resources>
        <!-- Base application theme -->
        <style name="Theme.FullScreenActivitySimulation" parent="Theme.Material3.DayNight.NoActionBar">
            <!-- Customize your theme here -->
            <item name="android:colorPrimary">@color/purple_500</item>
            <item name="colorPrimary">@color/purple_500</item>
            <item name="colorPrimaryVariant">@color/purple_700</item>
            <item name="colorOnPrimary">@color/white</item>
        </style>
    
        <!-- Custom theme for transparent activity -->
        <style name="Theme.AppCompat.Transparent" parent="Theme.AppCompat.NoActionBar">
            <item name="android:windowBackground">@android:color/transparent</item>
            <item name="android:windowIsTranslucent">true</item>
            <item name="android:windowNoTitle">true</item>
            <item name="android:windowFullscreen">true</item>
        </style>
    </resources>
    
    1. Create the Gradient Stroke Drawable

    Define a drawable resource for the gradient border effect.

    res/drawable/gradient_stroke.xml:

    <?xml version="1.0" encoding="utf-8"?>
    <layer-list xmlns:android="http://schemas.android.com/apk/res/android">
        <!-- Background color to make the center transparent -->
        <item>
            <shape android:shape="rectangle">
                <solid android:color="#00000000" />
            </shape>
        </item>
    
        <!-- Top Edge -->
        <item>
            <shape android:shape="rectangle">
                <gradient
                    android:centerY="0.03"
                    android:centerColor="@android:color/transparent"
                    android:startColor="#0000FF"
                    android:endColor="@android:color/transparent"
                    android:angle="90" />
            </shape>
        </item>
    
        <!-- Bottom Edge -->
        <item android:bottom="0dp">
            <shape android:shape="rectangle">
                <gradient
                    android:centerY="0.97"
                    android:centerColor="@android:color/transparent"
                    android:endColor="#0000FF"
                    android:startColor="@android:color/transparent"
                    android:angle="90" />
            </shape>
        </item>
    
        <!-- Left Edge -->
        <item>
            <shape android:shape="rectangle">
                <gradient
                    android:centerX="0.03"
                    android:centerColor="@android:color/transparent"
                    android:startColor="#0000FF"
                    android:endColor="@android:color/transparent"
                    android:angle="0" />
            </shape>
        </item>
    
        <!-- Right Edge -->
        <item android:right="0dp">
            <shape android:shape="rectangle">
                <gradient
                    android:centerX="0.97"
                    android:centerColor="@android:color/transparent"
                    android:endColor="#0000FF"
                    android:startColor="@android:color/transparent"
                    android:angle="0" />
            </shape>
        </item>
    </layer-list>
    
    1. Create the Layout for the Edge Lighting Activity

    Create a layout file for the EdgeLightingActivity that uses the gradient stroke drawable as its background.

    res/layout/activity_edge_lighting.xml:

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#00000000">
    
        <View
            android:id="@+id/edge_lighting_view"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="@drawable/gradient_stroke" />
    </RelativeLayout>
    
    1. Implement the Edge Lighting Activity

    Implement the EdgeLightingActivity to display the gradient stroke and automatically close after a few seconds.

    EdgeLightingActivity.kt:

    package com.example.fullscreenactivitysimulation
    
    import android.os.Bundle
    import android.os.Handler
    import android.os.Looper
    import android.util.Log
    import androidx.appcompat.app.AppCompatActivity
    import androidx.core.view.WindowCompat
    import androidx.core.view.WindowInsetsCompat
    import androidx.core.view.WindowInsetsControllerCompat
    
    class EdgeLightingActivity : AppCompatActivity() {
    
        private val TAG = "EdgeLightingActivity"
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            Log.d(TAG, "onCreate called")
    
            // Make the activity full-screen using WindowInsetsController
            WindowCompat.setDecorFitsSystemWindows(window, false)
            WindowInsetsControllerCompat(window, window.decorView).let { controller ->
                controller.hide(WindowInsetsCompat.Type.systemBars())
                controller.systemBarsBehavior = WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
            }
    
            setContentView(R.layout.activity_edge_lighting)
    
            // Set a timer to close the activity after a few seconds
            val handler = Handler(Looper.getMainLooper())
            handler.postDelayed({
                finish()
            }, 3000) // Show the edge lighting for 3 seconds
        }
    }
    
    1. Launch the Edge Lighting Activity from MainActivity

    Add a Floating Action Button (FAB) in MainActivity to launch the EdgeLightingActivity.

    MainActivity.kt:

    package com.example.fullscreenactivitysimulation
    
    import android.content.Intent
    import android.os.Bundle
    import androidx.activity.ComponentActivity
    import androidx.activity.compose.setContent
    import androidx.compose.foundation.layout.fillMaxSize
    import androidx.compose.foundation.layout.padding
    import androidx.compose.material3.FloatingActionButton
    import androidx.compose.material3.Icon
    import androidx.compose.material3.Scaffold
    import androidx.compose.material3.Text
    import androidx.compose.material3.icons.Icons
    import androidx.compose.material3.icons.filled.Add
    import androidx.compose.runtime.Composable
    import androidx.compose.ui.Modifier
    import androidx.compose.ui.tooling.preview.Preview
    import com.example.fullscreenactivitysimulation.ui.theme.FullScreenActivitySimulationTheme
    
    class MainActivity : ComponentActivity() {
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContent {
                FullScreenActivitySimulationTheme {
                    Scaffold(
                        modifier = Modifier.fillMaxSize(),
                        floatingActionButton = {
                            FloatingActionButton(
                                onClick = {
                                    val intent = Intent(this, EdgeLightingActivity::class.java)
                                    startActivity(intent)
                                }
                            ) {
                                Icon(Icons.Filled.Add, contentDescription = "Localized description")
                            }
                        }
                    ) { innerPadding ->
                        Greeting(
                            name = "Android",
                            modifier = Modifier.padding(innerPadding)
                        )
                    }
                }
            }
        }
    }
    
    @Composable
    fun Greeting(name: String, modifier: Modifier = Modifier) {
        Text(
            text = "Hello $name!",
            modifier = modifier
        )
    }
    
    @Preview(showBackground = true)
    @Composable
    fun GreetingPreview() {
        FullScreenActivitySimulationTheme {
            Greeting("Android")
        }
    }
    
    1. Declare the Custom Theme in AndroidManifest.xml

    Ensure the custom theme is applied to your activity in the manifest file.

    AndroidManifest.xml:

    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools">
    
        <application
            android:allowBackup="true"
            android:icon="@mipmap/ic_launcher"
            android:label="@string/app_name"
            android:roundIcon="@mipmap/ic_launcher_round"
            android:supportsRtl="true"
            android:theme="@style/Theme.FullScreenActivitySimulation">
            
            <activity
                android:name=".MainActivity"
                android:exported="true"
                android:theme="@style/Theme.AppCompat.Transparent">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
            
            <activity
                android:name=".EdgeLightingActivity"
                android:theme="@style/Theme.AppCompat.Transparent" />
            
        </application>
    </manifest>
    

    To ensure the gradient border is only viewable for a set amount of time after a button click in Method 2, you can programmatically add the border view, display it for a specified duration, and then remove it.

    Here's how to modify the implementation to achieve this:

    Method 2: Drawing Directly to the Main Activity

    You can also draw directly to the screen by setting the appropriate theme in the main activity, which controls the total area the app will draw.

    Pros:

    • Does not interfere with the main activity's UI.

    Cons:

    • Requires proper theme configuration for edge-to-edge control.

    Step-by-Step Implementation

    1. Ensure the Custom Theme is Defined

    Ensure you have the custom theme defined as shown in Method 1.

    1. Update the Main Activity Layout

    Modify your main activity layout to include a FrameLayout that overlays the gradient border drawable on top of your main content.

    <!-- res/layout/activity_main.xml -->
    <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    
        <!-- Main content goes here -->
        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent">
    
            <!-- Your main content here -->
            <!-- Example: -->
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Hello, World!"
                android:layout_centerInParent="true" />
    
        </RelativeLayout>
    
        <!-- Gradient border overlay, initially invisible -->
        <View
            android:id="@+id/gradient_border_view"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="@drawable/gradient_stroke"
            android:visibility="gone" />
    
        <!-- FloatingActionButton to trigger the border display
        <com.google.android.material3.FloatingActionButton -->
        <!-- FloatingActionButton to trigger the border display -->
        <com.google.android.material.floatingactionbutton.FloatingActionButton
            android:id="@+id/fab"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="bottom|end"
            android:layout_margin="16dp"
            android:src="@android:drawable/ic_input_add" />
    </FrameLayout>
    
    1. MainActivity Implementation

    Add functionality to display the gradient border for a set amount of time after a button click.

    // MainActivity.kt
    package com.example.fullscreenactivitysimulation
    
    import android.os.Bundle
    import android.os.Handler
    import android.os.Looper
    import android.view.View
    import androidx.appcompat.app.AppCompatActivity
    import com.google.android.material.floatingactionbutton.FloatingActionButton
    
    
    class MainActivity : AppCompatActivity() {
        private lateinit var gradientBorderView: View
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main)
    
            gradientBorderView = findViewById(R.id.gradient_border_view)
    
            val fab: FloatingActionButton = findViewById(R.id.fab)
            fab.setOnClickListener {
                showGradientBorderForLimitedTime(3000) // Show for 3 seconds
            }
        }
    
        private fun showGradientBorderForLimitedTime(duration: Long) {
            gradientBorderView.visibility = View.VISIBLE
            Handler(Looper.getMainLooper()).postDelayed({
                gradientBorderView.visibility = View.GONE
            }, duration)
        }
    }
    
    1. Declare the Custom Theme in AndroidManifest.xml

    Ensure the custom theme is applied to your activity in the manifest file.

    <!-- AndroidManifest.xml -->
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools">
    
        <application
            android:allowBackup="true"
            android:icon="@mipmap/ic_launcher"
            android:label="@string/app_name"
            android:roundIcon="@mipmap/ic_launcher_round"
            android:supportsRtl="true"
            android:theme="@style/Theme.AppCompat">
    
            <activity
                android:name=".MainActivity"
                android:exported="true"
                android:theme="@style/Theme.AppCompat.NoActionBar">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
    
        </application>
    </manifest>
    

    Summary

    Method 1: Using a Second Activity

    • Create a second activity with a custom theme to display a gradient border.

    Method 2: Drawing Directly to the Main Activity

    • Directly draw the gradient border in the main activity using a FrameLayout and proper theme configuration.
    • Programmatically show the border for a limited time after a button click.

    By following these steps, you can create a transparent, gradient border directly on your main activity, achieving a clean and integrated effect without the need for a separate activity. The border will only be viewable for a set amount of time after the button is clicked.