Showing posts with label android. Show all posts
Showing posts with label android. Show all posts

Tuesday, November 11, 2025

Android java: using DataLive for orientation change

I test it in Android 10 xiaomi mia2

What will happen when orientation change e.g. screen change or language change?

the object in activity will be destroyed. here is the sequence:

  • after orientation change
    V  onPause
    V  onStop
    V  onDestrouy
  • after flusing all data
    V  onCreate
    V  onCreate myClass :null
    V  MyClass constructor
    V  onCreateView myClass.getRandom
    V  onStart
    V  onResume 

At xiomi mia2, override public void onConfigurationChanged(Configuration newConfig) method did not called at all during screen orientation change, not appearred in logcat. except, you put android:configChanges in your layout.

Base on the android behave, these are the solution can be used to keep the object during configuration change:

  1. Local persistence to handle process death for complex or large data. Persistent local storage includes databases or DataStore.
  2. Retained objects such as ViewModel instances to handle UI-related state in memory while the user is actively using the app.
  3. Saved instance state to handle system-initiated process death and keep transient state that depends on user input or navigation. 

ViewModel is recommended used for today an future, These are some options:

  1. ViewModel    Holds UI data & logic    Core architecture component
  2. ComputableLiveData (Deprecated)
  3. MediatorLiveData    Combines multiple LiveData sources    Merging streams
  4. MutableLiveData    Observable, mutable data    UI updates
  5. SavingStateLiveData    LiveData with saved-state persistence    Restore after process death 

Comparison between AndroidViewModel vss ViewModel

AndroidViewModel require Context for DB, prefs, etc. gemini: Avoid if possible. Only use when you absolutely need Context. violates a core principle of good architecture: separation of concerns and testability.
ViewModel UI logic without needing Context Network requirement may use this, it does not need context

NOTE: Don’t store Activity or Fragment in VieModel nor AndroidViewModel! 

These are the java code for education, first text using direct access to object in activity, and second text using live data and AndroidViewModel. this code used AndroidViewModel, because I need application's context to access sqlite.

-- MyClass.java

package com.dedetok.testdataorientation;

import android.content.Context;
import android.util.Log;

import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;

import java.util.Random;

public class MyClass {
    // dummy
    Context context;

    boolean isCreated = false;
    int randomNumber=-1;

    public MyClass(Context context) {
        this.context = context;
        Log.v("deddetok", "MyClass constructor"); // debug

    }

    public String getRandom() {
        if (!isCreated) {
            Random random = new Random();
            randomNumber = random.nextInt(100);
            isCreated = true;
        }
        return String.valueOf(randomNumber);
    }

    public LiveData<String> getRandomLive() {
        if (!isCreated) {
            Random random = new Random();
            randomNumber = random.nextInt(100);
            isCreated = true;
        }
        MutableLiveData<String> returnValue = new MutableLiveData<>();
        returnValue.setValue(String.valueOf(randomNumber));

        return returnValue;
    }
}

-- MyAndroidViewModel

package com.dedetok.testdataorientation;

import android.app.Application;

import androidx.annotation.NonNull;
import androidx.lifecycle.AndroidViewModel;
import androidx.lifecycle.LiveData;

public class MyAndroidViewModel extends AndroidViewModel {
    MyClass myClass;

    public MyAndroidViewModel(@NonNull Application application) {
        super(application);
        myClass = new MyClass(application);
    }

    public LiveData<String> getData() {
        return myClass.getRandomLive();
    }
}

-- MainActivity.java

package com.dedetok.testdataorientation;

import android.content.Context;
import android.content.res.Configuration;
import android.os.Bundle;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import androidx.activity.EdgeToEdge;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.AppCompatTextView;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
import androidx.lifecycle.ViewModelProvider;

public class MainActivity extends AppCompatActivity {

    MyClass myClass = null;

    AppCompatTextView myTextView1, myTextView2;

    MyAndroidViewModel myAndroidViewModel;

    /* to preserve myclass
     * 1. Local persistence to handle process death for complex or large data. Persistent local storage includes databases or DataStore.
     * 2. Retained objects such as ViewModel instances to handle UI-related state in memory while the user is actively using the app.
     * 3. Saved instance state to handle system-initiated process death and keep transient state that depends on user input or navigation.
     */

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        EdgeToEdge.enable(this);
        setContentView(R.layout.activity_main);
        ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {
            Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
            v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
            return insets;
        });

        Log.v("dedetok", "onCreate"); // debug


        myTextView1 = findViewById(R.id.textView1);
        myTextView2 = findViewById(R.id.textView2);

        Log.v("dedetok", "onCreate myClass :"+myClass); //
        // myTextView1
        if (myClass==null) {
            myClass = new MyClass(this);
        }
        myTextView1.setText(myClass.getRandom()); // work, created in memory

        // ✅ Get ViewModel (it survives rotation)
        // myTextView2
        myAndroidViewModel = new ViewModelProvider(this).get(MyAndroidViewModel.class);
        myAndroidViewModel.getData().observe(this, value -> {
            // 'value' is a plain String here
            myTextView2.setText(value);
        }); //

    }

    @Nullable
    @Override
    public View onCreateView(@Nullable View parent, @NonNull String name, @NonNull Context context, @NonNull AttributeSet attrs) {
        Log.v("dedetok", "onCreateView"); // debug
        //Log.v("dedetok", "onCreateView myClass.getRandom"); // debug
        //myTextView.setText(myClass.getRandom()); // crash textview not ready
        return super.onCreateView(parent, name, context, attrs);
    }

    /*
     * ## activity life cycle 2 ##
     */
    @Override
    protected void onStart() {
        super.onStart();
        Log.v("dedetok", "onCreateView myClass.getRandom"); // debug
        //myTextView1.setText(myClass.getRandom()); // work, view has been created
        myAndroidViewModel.getData().observe(this, value -> {
            // 'value' is a plain String here
            myTextView2.setText(value);
        }); // this is fine place

        Log.v("dedetok", "onStart"); // debug

    }

    /*
     * ## activity life cycle 3 ##
     */
    @Override
    protected void onResume() {
        super.onResume();

        Log.v("dedetok", "onResume"); // debug


    }

    /*
     * ## activity life cycle 4 ##
     */
    @Override
    protected void onPause() {
        Log.v("dedetok", "onPause"); // debug
        super.onPause();

    }

    /*
     * ## activity life cycle 5 ##
     */
    @Override
    protected void onStop() {
        Log.v("dedetok", "onStop"); // debug
        super.onStop();

    }

    /*
     * ## activity life cycle 6 ##
     */
    @Override
    protected void onDestroy() {
        Log.v("dedetok", "onDestrouy"); // debug

        super.onDestroy();
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        Log.v("dedetok", "onConfigurationChanged"); // debug
    }
}

-- activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <androidx.appcompat.widget.AppCompatTextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="TextView"
        android:minHeight="50dp"
        android:textSize="24sp"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        />
    <androidx.appcompat.widget.AppCompatTextView
        android:id="@+id/textView2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="TextView2"
        android:minHeight="50dp"
        android:textSize="24sp"
        app:layout_constraintTop_toBottomOf="@+id/textView1"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        />
</androidx.constraintlayout.widget.ConstraintLayout>

Some of parts of this content generated by ChatGPT and Gemini with some modification.

Wednesday, November 5, 2025

Android Studio: using Logcat and filter

 

LevelPriorityUse Case
Log.v()Verbose (V)Everything. Detailed tracing of functions, variable values, lifecycle events.
Log.d()Debug (D)General debugging messages useful for development.
Log.i()Info (I)Important business logic messages, typical user actions, system state changes.
Log.w()Warn (W)Use of deprecated APIs, non-critical errors that can be recovered.
Log.e()Error (E)Critical errors that cause a failure or stop a feature from working.
Log.wtf()Assert (A)What a Terrible Failure. Reserved for conditions that should never happen.

Option to filter in Andorid Studio Logcat

  1. tag: Filters messages by a specific log tag.
    Example: tag:MyActivity
  2. level: Filters messages at the specified log level or higher. Levels include VERBOSE (V), DEBUG (D), INFO (I), WARN (W), ERROR (E), and ASSERT (A).
    Example: level:ERROR (shows ERROR and ASSERT logs)
  3. process: Filters messages by the process name or process ID (PID).
    Example: process:1234 or process:com.example.app
  4. age: Filters messages by how recent they are. The value is a number followed by a unit of time: s (seconds), m (minutes), h (hours), or d (days).
    Example: age:5m (shows messages from the last 5 minutes)
  5. is: Can be used with crash to filter only crash logs.
    Example: is:crash
  6. package: A convenient shortcut to filter logs only from the currently running application's package. 

Logical operation can be use in Logcat Filter

  1. && (AND): Requires both conditions to be true.
    Example: package:mine && level:WARN
  2. | (OR): Requires at least one condition to be true.
    Example: tag:Tag1 | tag:Tag2
  3. - (NOT/Exclude): Excludes logs matching the condition. Place the hyphen before the key.
    Example: -tag:ExcludedTag

Example usage Logcat filter:

  1. package:mine level:INFO "user data" -tag:network
  2. tag:MyTag && level:DEBUG || is:crash 

Credit: Table conversion to html online http://the-mostly.ru/online_html_table_generator.html

Tuesday, October 14, 2025

Android Studio 2024.1.4: backup and how you migrate your old project

Android Studio move so fast, the developer and ide tools are racing each other.

These are must you backup: 

  1. Project name
  2. Your key file i.e jks for your project
  3. your project source
    1. <root_app> remove folders .gradle .idea and build, remove file .gitignore
    2. <root_app>/app remove folders build, libs and release, remove file .gitignore
    3. <root_app>/gradle remove file ./gradle/wrapper/gradle-wrapper.jar

For upgrading from old project, and your project does not have libs.versions.toml file:

  1. Create it (see below) or copy from other project <root_app>/gradle/libs.versions.toml.
  2. change build.gradle.kts (:app)
    plugins {
        id("com.android.application")
    }
    into 
    plugins {
        alias(libs.plugins.android.application)
    }
    Change dependency 
    dependencies {

        implementation("androidx.appcompat:appcompat:1.7.1")
        implementation("com.google.android.material:material:1.12.0")
        implementation("androidx.constraintlayout:constraintlayout:2.2.1")
        testImplementation("junit:junit:4.13.2")
        androidTestImplementation("androidx.test.ext:junit:1.2.1")
        androidTestImplementation("androidx.test.espresso:espresso-core:3.6.1")
        implementation("com.google.android.gms:play-services-ads-lite:24.0.0")

    }
    into
    dependencies {

        implementation(libs.appcompat)
        implementation(libs.material)
        testImplementation(libs.junit)
        androidTestImplementation(libs.ext.junit)
        androidTestImplementation(libs.espresso.core)

        // admob
        implementation(libs.play.services.ads)
    }
  3. Update your libs.versions.toml, revise the version if necessary:
    [versions]
    agp = "8.13.0"
    junit = "4.13.2"
    junitVersion = "1.3.0"
    espressoCore = "3.7.0"
    appcompat = "1.7.1"
    material = "1.13.0"
    playServicesAds = "24.7.0"

    [libraries]
    junit = { group = "junit", name = "junit", version.ref = "junit" }
    ext-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" }
    espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" }
    appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" }
    material = { group = "com.google.android.material", name = "material", version.ref = "material" }
    play-services-ads = { module = "com.google.android.gms:play-services-ads", version.ref = "playServicesAds" }

    [plugins]
    android-application = { id = "com.android.application", version.ref = "agp" }

Note: if you have other external dependency, keep the library first, and migrate after common library successfully upgraded.

To create libs.versions.toml, at left side Project Files -> gradle -> New -> File, name it with: libs.versions.toml. Continue step 2 above.

This is example of external library, how to move jsoup into libs.versions.toml

Change build.gradle.kts (:app) from  

dependencies {
    ...
    implementation("org.jsoup:jsoup:
1.21.2") // jsoup

}

change into

dependencies {
    ....
    implementation(libs.jsoup)
}

And add into libs.versions.toml

[versions]
...
# Define the version number
jsoup = "1.21.2"
...
[libraries]
...
# Define the library coordinates, referencing the version above
jsoup = { group = "org.jsoup", name = "jsoup", version.ref = "jsoup" }
...

 

Friday, October 10, 2025

Debian 13: Configure NVidia in dual gpu - hybrid mode and how to utilize it in Android Studio

List your VGA: 

# lspci | grep -E "VGA|3D"
01:00.0 VGA compatible controller: NVIDIA Corporation GA107 [GeForce RTX 2050] (rev a1)
05:00.0 VGA compatible controller: Advanced Micro Devices, Inc. [AMD/ATI] Rembrandt [Radeon 680M] (rev 0b)

Installation

# apt-get install firmware-nvidia-graphics nvidia-detect nvidia-driver linux-headers-$(uname -r) vulkan-tools

Warning "Conflicting nouveau kernel module loaded" may appear.

Check your nvidia

# nvidia-detect
Detected NVIDIA GPUs:
01:00.0 VGA compatible controller [0300]: NVIDIA Corporation GA107 [GeForce RTX 2050] [10de:25ad] (rev a1)

Checking card:  NVIDIA Corporation GA107 [GeForce RTX 2050] (rev a1)
Your card is supported by all driver versions.
Your card is also supported by the Tesla 535 drivers series.
It is recommended to install the
    nvidia-driver

Chek your nvidia software

# nvidia-smi
Fri Oct 10 23:07:14 2025       
+-----------------------------------------------------------------------------------------+
| NVIDIA-SMI 550.163.01             Driver Version: 550.163.01     CUDA Version: 12.4     |
|-----------------------------------------+------------------------+----------------------+
| GPU  Name                 Persistence-M | Bus-Id          Disp.A | Volatile Uncorr. ECC |
| Fan  Temp   Perf          Pwr:Usage/Cap |           Memory-Usage | GPU-Util  Compute M. |
|                                         |                        |               MIG M. |
|=========================================+========================+======================|
|   0  NVIDIA GeForce RTX 2050        On  |   00000000:01:00.0 Off |                  N/A |
| N/A   40C    P0              7W /   45W |       9MiB /   4096MiB |      0%      Default |
|                                         |                        |                  N/A |
+-----------------------------------------+------------------------+----------------------+

Note: run glxinfo in "xfce terminal", not "terminal emulator"  

GLX information

$ glxinfo | grep "OpenGL renderer"
OpenGL renderer string: AMD Radeon 660M (radeonsi, rembrandt, LLVM 19.1.7, DRM 3.61, 6.12.31-amd64)

The desktop will utilize AMD GPU, we want to run Android Studio and utilize GeForce RTX 2050. Create a bash script to run Android Studio using NVidia Geforce RTX2050 instead build in AMD gpu, e.q 

#!/bin/bash
# Launch Android Studio using the NVIDIA GPU (Prime Render Offload)

APP_PATH="$HOME/AndroidStudio/android-studio/bin/studio.sh"

if [ ! -f "$APP_PATH" ]; then
    echo "Error: Android Studio not found at $APP_PATH"
    exit 1
fi

# Run Android Studio with NVIDIA GPU offload
__NV_PRIME_RENDER_OFFLOAD=1 __GLX_VENDOR_LIBRARY_NAME=nvidia "$APP_PATH" &

Usefull command if any systemd error during boot 

# journalctl -b -u systemd-modules-load.service


Saturday, May 3, 2025

Removing bloatware in Android

It is common, every non AOSP android may come with ton of partner's application. The applications are known as bloatware.

Some bloatwares can be uninstall. Or some can only be disable. However, bloatware with disable can still running on background.  

Those bloatwares are used your mobile phone resource. These are steps to remove/uninstall from your mobile using PC, any operation system that can run adb (Android Debugging Bridge). I Assume, you done this.

You must enable development mode and USB Debugging your mobile phone.

Development mode
USB Debugging

Afteer you connect your mobile phone to your PC using USB, from your mobile, you need to trust your PC to make connection and run debugging, include running script via adb.

AllowUSB Debugging

Open your terminal and go to directory where your ADB tool install or placed, e.q. D:\android\sdk\platform-tools. Follow this command

1. detect your android phone

>adb devices
List of devices attached
1xxxxxxxxxxxxxxx        device

2. connect to your device

>adb shell
TECNO-KJ6:/ $

3. run pm to remove bloatware

$ pm uninstall --user 0 com.transsnet.store
Success

4. exit

$ exit
>

To View packages

$ pm list packages | grep store
package:com.google.android.apps.restore
package:com.transsnet.store

This is screen shoot status of application after deletion.

Getting package name
After removing/deletion

You need to know the package name you want to remove. Pick any application you wish in play store with key search "Application Inspector"

Bloatware Table

Application Package Name Tecno Spark 20 Pro KJ6 Infinix note 12 x670
AHA Games net.bat.store n y
Folax com.transsion.aivoiceassistant n y
Hola Browser com.talpa.hibrowser y y
Palm Store com.transsnet.store y y
Visha Player com.transsion.magicshow n y
WeZone com.transsion.wezone n y


NOTE:

  1. The bloatware status uninstall after restart your android
  2. The bloatware still exist in rom, every time you reset your android, the bloatware will come up. You need to re do all steps to remove it.

Reference: https://www.phoneworld.com.pk/the-truth-about-xos-how-infinixs-ui-is-burdened-by-excessive-bloatware/

 

Friday, September 27, 2024

android java: google admob policy collected data checklist

 

In May 2021, Google Play announced the new Data safety section https://developers.google.com/admob/android/privacy/play-data-disclosure. All application must declare data safety, include if application has 3rd partly like Google Google Mobile Ads.

Unfortunately, the guidance data disclosure in https://developers.google.com/admob/android/privacy/play-data-disclosure does not clear. It does mention clues what Google Mobile Ads SDK do with our client data. Here are the clues:

Data

By default, the Google Mobile Ads SDK...

IP address

Collects device's IP address, which may be used to estimate the general location of a device.

User product interactions

Collects user product interactions and interaction information, including app launch, taps, and video views.

Diagnostic information

Collects information related to the performance of your app and the SDK, including crash logs, app launch time, hang rate, and energy usage.

Device and Account identifiers

Collects Android advertising (ad) ID, app set ID, and, if applicable, other identifiers related to signed-in accounts on the device.

We must fill in Data safety section:

A.    Overview
Information about what to fill.

B.    Data Collection and Security

1.     Does your app collect or share any of the required user data types? Y

·       Is all of the user data collected by your app encrypted in transit? Y

·       þ My app does not allow users to create an account

       Can users login to your app with accounts created outside of the app? N

·       Do you provide a way for users to request that their data is deleted? (Optional) N

C.    Data Types

1.     Location:

·       Approximate location

2.     Personal info:

·       User IDs

·       Other info

3.     App activity:

·       App interactions

·       In-app search history

·       Installed apps

4.     App info and performance:

·       Crash logs

·       Diagnostics

·       Other app performance data

5.     Device or other IDs

·       Device or other IDs

D.    Data usage and handling

1.     Personal info - User IDs & Other info

·       Is this data collected, shared, or both?
þ Collected & Shared

·       Is this data processed ephemerally?
þ No, this collected data is not processed ephemerally

·       Is this data required for your app, or can users choose whether it's collected?
þ Data collection is required (users can't turn off this data collection)

·       Why is this user data collected? Select all that apply.
þ Advertising or marketing

·       Why is this user data shared? Select all that apply.
þ Advertising or marketing

2.     Location - Approximate location:

·       Is this data collected, shared, or both?
þ Collected & Shared

·       Is this data processed ephemerally?
þ No, this collected data is not processed ephemerally

·       Is this data required for your app, or can users choose whether it's collected?
þ Data collection is required (users can't turn off this data collection)

·       Why is this user data collected? Select all that apply.
þ Advertising or marketing

·       Why is this user data shared? Select all that apply.
þ Advertising or marketing

3.     App info and performance - Crash logs; Diagnostics; & Other app performance data

·       Is this data collected, shared, or both?
þ Collected & Shared

·       Is this data processed ephemerally?
þ No, this collected data is not processed ephemerally

·       Is this data required for your app, or can users choose whether it's collected?
þ Data collection is required (users can't turn off this data collection)

·       Why is this user data collected? Select all that apply.
þ Analytics

·       Why is this user data shared? Select all that apply.
þ Analytics

4.     App activity - App interactions; In-app search history; & Installed apps

·       Is this data collected, shared, or both?
þ Collected & Shared

·       Is this data processed ephemerally?
þ No, this collected data is not processed ephemerally

·       Is this data required for your app, or can users choose whether it's collected?
þ Data collection is required (users can't turn off this data collection)

·       Why is this user data collected? Select all that apply.
þ Advertising or marketing

·       Why is this user data shared? Select all that apply.
þ Advertising or marketing

5.     Device or other IDs - Device or other IDs:

·       Is this data collected, shared, or both?
þ Collected & Shared

·       Is this data processed ephemerally?
þ No, this collected data is not processed ephemerally

·       Is this data required for your app, or can users choose whether it's collected?
þ Data collection is required (users can't turn off this data collection)

·       Why is this user data collected? Select all that apply.
þ Advertising or marketing

·       Why is this user data shared? Select all that apply.
þ Advertising or marketing