Friday, February 13, 2026

java: comparison between database api in java android and jdbc in java standard edition

Here is comparison between database api in java android and jdbc in java standard edition  

Operation

Java Android

Java SE (JDBC)

INSERT

Returns new row ID (long)

Returns affected rows (int)

UPDATE

Returns affected rows (int)

Same

DELETE

Returns affected rows (int)

Same                      

In java SE (JDBC) id can be retrive using jse ps.getGeneratedKeys() return long where ps is PreparedStatement.

 

Android java: notification pattern code

add permission in project 

AndroidManifest.xml

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

MainActivity.java 

   @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;
        });

        checkPermissions();
    ....
    }



    /*
     * check permission to read contact and write shared folder Download
     */
    private void checkPermissions() {
        List<String> permissions = new ArrayList<>();

        // 1. Android 13+ Notification Permission
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
            permissions.add(Manifest.permission.POST_NOTIFICATIONS);
        }

        // API require string convert List<String> to String[];
        requestPermissionLauncher.launch(permissions.toArray(new String[0]));
    }

    /*
     * callback permission request
     */
    private final ActivityResultLauncher<String[]> requestPermissionLauncher =
            registerForActivityResult(new ActivityResultContracts.RequestMultiplePermissions(), result -> {
                // Handle Notification permission (Android 13+)
                boolean notificationsGranted = true;
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
                    notificationsGranted = result.getOrDefault(Manifest.permission.POST_NOTIFICATIONS, false);
                }

            }); 

create MyNotificationService.java class

public class MyNotificationService {

    public static final String CHANNEL_ID = "id_string_channel"; // todo
    public static final int NOTIF_ID = 123456;  // todo

    /*
     * to send notification
     */
    public static void sendNotification(Context context, String title, String message) {
        NotificationManager notificationManager =
                (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);

        NotificationCompat.Builder myNotifBuilder = getNotificationBuilder(context);
        myNotifBuilder
                .setContentTitle(title)
                .setContentText(message);

        notificationManager.notify(NOTIF_ID, myNotifBuilder.build());
    }

    /*
     * get notification for foreground
     */
    public static Notification getForegroundNotification(Context context) {
        Notification myNotif = getNotificationBuilder(context).build();
        return myNotif;
    }
    
    /*
     * Helper that returns the BUILDER so you can customize it before building
     */
    private static NotificationCompat.Builder getNotificationBuilder(Context context) {
        NotificationManager notificationManager =
                (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            if (notificationManager.getNotificationChannel(CHANNEL_ID) == null) {
                NotificationChannel notifChannel = new NotificationChannel(
                        CHANNEL_ID,
                        "Background Sync Service",
                        NotificationManager.IMPORTANCE_LOW
                );
                notificationManager.createNotificationChannel(notifChannel);
            }
        }

        return new NotificationCompat.Builder(context, CHANNEL_ID)
                .setSmallIcon(android.R.drawable.stat_notify_sync)
                .setPriority(NotificationCompat.PRIORITY_LOW)
                .setCategory(Notification.CATEGORY_SERVICE);
        //.setOngoing(true); // can not swap away
    }

 

 

Thursday, February 12, 2026

Android java: layout collection

Fragment

use just portrait for phone and w600 for tablet (bigger screen)   

for portrait (phone) 

<?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.LinearLayoutCompat
    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"
    android:orientation="vertical"
    >
    
    <!-- Top TextView -->
    <TextView
        android:id="@+id/top_text"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Your Title Here"
        android:textSize="18sp"
        android:textStyle="bold"
        android:padding="12dp"
        android:gravity="center"
        android:background="#DDDDDD" />
    
    <androidx.fragment.app.FragmentContainerView
        android:id="@+id/my_fragment_container_main"
        android:name="[Your java main fragment with full package name]"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        />

</androidx.appcompat.widget.LinearLayoutCompat>

for w600 tablet

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <!-- Top TextView -->
    <TextView
        android:id="@+id/top_text"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Your Title Here"
        android:textSize="18sp"
        android:textStyle="bold"
        android:padding="12dp"
        android:gravity="center"
        android:background="#DDDDDD" />

    <!-- Horizontal Content -->
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:orientation="horizontal"
        android:weightSum="3">

    <androidx.fragment.app.FragmentContainerView
        android:id="@+id/my_fragment_container_left"
        android:name="[Your java left fragment with full package name]"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1" />

    <View
        android:id="@+id/divider_line"
        android:layout_width="1dp"
        android:layout_height="match_parent"
        android:background="#000000" />

    <androidx.fragment.app.FragmentContainerView
        android:id="@+id/my_fragment_container_main"
        android:name="[Your java main fragment with full package name]"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="2" />

    </LinearLayout>

</LinearLayout> 

in main activity on onCreate(Bundle savedInstanceState)

    FragmentManager fragmentManager = getSupportFragmentManager();
    public boolean isDualPane = false; // default is portrait

    @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;
        });

        isDualPane = findViewById(R.id.my_fragment_container_left) != null;

        // R.id.main id for root portrait & w600
        

        // Load Fragments only if this is a fresh start (savedInstanceState == null)
        // This prevents overlapping fragments during screen rotation
        if (savedInstanceState == null) {
            FragmentTransaction transaction = fragmentManager.beginTransaction();


            // If system loaded the w600 layout, load both Fragment
            if (isDualPane) {
                transaction.replace(R.id.my_fragment_container_left, new [Your java left fragment with full package name]);
                transaction.replace(R.id.my_fragment_container_main, new [Your java main fragment with full package name]);
            } else {
                // default load main container
                transaction.replace(R.id.my_fragment_container_main, new [Your java main fragment with full package name]);
            }
            transaction.commit();
        }
        ....

Add this and fix 

private void replaceFragment(int containerId,

                             Fragment fragment,

                             boolean addToBackStack) {


    FragmentTransaction transaction =

            getSupportFragmentManager().beginTransaction();


    transaction.replace(containerId, fragment);


    if (addToBackStack) {

        transaction.addToBackStack(null);

    }


    transaction.commit();

}



 to implement onbackpresseddispatcher pattern code, see this  https://dedetoknotes.blogspot.com/2026/01/android-java-onbackpresseddispatcher.html

 

Saturday, February 7, 2026

Debian 13: removing kernel left over after kernel upgrade

wifi and some device require compile in debian depend on kernel version. this documentation is intended as a small guide to tidy up your system.

list of ii and rc status of package

# uname -r
6.12.63+deb13-amd64
# dpkg -l | grep linux-image
rc  linux-image-6.1.0-33-amd64                         6.1.133-1                            amd64        Linux 6.1 for 64-bit PCs (signed)
rc  linux-image-6.1.0-34-amd64                         6.1.135-1                            amd64        Linux 6.1 for 64-bit PCs (signed)
rc  linux-image-6.1.0-37-amd64                         6.1.140-1                            amd64        Linux 6.1 for 64-bit PCs (signed)
rc  linux-image-6.1.0-9-amd64                          6.1.27-1                             amd64        Linux 6.1 for 64-bit PCs (signed)
rc  linux-image-6.12.38+deb13-amd64                    6.12.38-1                            amd64        Linux 6.12 for 64-bit PCs (signed)
rc  linux-image-6.12.38+deb13-amd64-unsigned           6.12.38-1                            amd64        Linux 6.12 for 64-bit PCs
rc  linux-image-6.12.41+deb13-amd64                    6.12.41-1                            amd64        Linux 6.12 for 64-bit PCs (signed)
rc  linux-image-6.12.41+deb13-amd64-unsigned           6.12.41-1                            amd64        Linux 6.12 for 64-bit PCs
rc  linux-image-6.12.43+deb13-amd64                    6.12.43-1                            amd64        Linux 6.12 for 64-bit PCs (signed)
rc  linux-image-6.12.43+deb13-amd64-unsigned           6.12.43-1                            amd64        Linux 6.12 for 64-bit PCs
rc  linux-image-6.12.48+deb13-amd64                    6.12.48-1                            amd64        Linux 6.12 for 64-bit PCs (signed)
rc  linux-image-6.12.48+deb13-amd64-unsigned           6.12.48-1                            amd64        Linux 6.12 for 64-bit PCs
rc  linux-image-6.12.57+deb13-amd64                    6.12.57-1                            amd64        Linux 6.12 for 64-bit PCs (signed)
ii  linux-image-6.12.57+deb13-amd64-unsigned           6.12.57-1                            amd64        Linux 6.12 for 64-bit PCs
ii  linux-image-6.12.63+deb13-amd64                    6.12.63-1                            amd64        Linux 6.12 for 64-bit PCs (signed)
ii  linux-image-amd64                                  6.12.63-1                            amd64        Linux for 64-bit PCs (meta-package)

Note about rc and ii 

  • rc = package removed, but config files remain
  • ii = desired state install and current state installed 

we can conclude these packages are not used anymore but still exist in our system:

  1. rc linux-image-6.1.0-*
  2. rc linux-image-6.12.38*
  3. rc linux-image-6.12.41*
  4. rc linux-image-6.12.43*
  5. rc linux-image-6.12.48*

We can remove those packages which is kernel left over, using this command:

# dpkg -l | awk '/^rc  linux-image/ {print $2}' | xargs dpkg --purge
(Reading database ... 180811 files and directories currently installed.)
Purging configuration files for linux-image-6.1.0-33-amd64 (6.1.133-1) ...
Purging configuration files for linux-image-6.1.0-34-amd64 (6.1.135-1) ...
Purging configuration files for linux-image-6.1.0-37-amd64 (6.1.140-1) ...
Purging configuration files for linux-image-6.1.0-9-amd64 (6.1.27-1) ...
dpkg: warning: while removing linux-image-6.1.0-9-amd64, directory '/lib/modules' not empty so not removed
Purging configuration files for linux-image-6.12.38+deb13-amd64 (6.12.38-1) ...
Purging configuration files for linux-image-6.12.38+deb13-amd64-unsigned (6.12.38-1) ...
rmdir: failed to remove '/lib/modules/6.12.38+deb13-amd64': No such file or directory
Purging configuration files for linux-image-6.12.41+deb13-amd64 (6.12.41-1) ...
Purging configuration files for linux-image-6.12.41+deb13-amd64-unsigned (6.12.41-1) ...
rmdir: failed to remove '/lib/modules/6.12.41+deb13-amd64': No such file or directory
Purging configuration files for linux-image-6.12.43+deb13-amd64 (6.12.43-1) ...
Purging configuration files for linux-image-6.12.43+deb13-amd64-unsigned (6.12.43-1) ...
rmdir: failed to remove '/lib/modules/6.12.43+deb13-amd64': No such file or directory
Purging configuration files for linux-image-6.12.48+deb13-amd64 (6.12.48-1) ...
Purging configuration files for linux-image-6.12.48+deb13-amd64-unsigned (6.12.48-1) ...
rmdir: failed to remove '/lib/modules/6.12.48+deb13-amd64': No such file or directory
Purging configuration files for linux-image-6.12.57+deb13-amd64 (6.12.57-1) ...
I: /vmlinuz is now a symlink to boot/vmlinuz-6.12.63+deb13-amd64
I: /initrd.img is now a symlink to boot/initrd.img-6.12.63+deb13-amd64
rmdir: failed to remove '/lib/modules/6.12.57+deb13-amd64': Directory not empty

 

 

Saturday, January 31, 2026

Debian 13: using unbound as DNS over https resolver in conjuction with NetworkManager and Systemd Resolved

Assume:

  • NetworkManager and Systemd-Resolved already work 

Install unbound

# apt-get install unbound

Edit /etc/systemd/resolved.conf and set:

[Resolve]
DNS=127.0.0.1:5335
Domains=~.

Make sure this line in /etc/unbound/unbound.conf

...
include-toplevel: "/etc/unbound/unbound.conf.d/*.conf"
...

Create and edit /etc/unbound/unbound.conf.d/google-doh.conf

server:
    # Port 5335 is safer for laptops than 5353 (mDNS)
    port: 5335
    interface: 127.0.0.1
    access-control: 127.0.0.0/8 allow
    
    # Required for TLS verification
    tls-cert-bundle: "/etc/ssl/certs/ca-certificates.crt"
forward-zone:
name: "."
    # Using DoT (Port 853) instead of DoH (Port 443)
    forward-tls-upstream: yes
    forward-addr: 8.8.8.8@853#dns.google
    forward-addr: 8.8.4.4@853#dns.google

Enable unbound and restart all services

# systemctl enable unbound
# systemctl start unbound
# systemctl restart systemd-resolved
# systemctl restart NetworkManager

Test

# resolvectl query google.com
google.com: 172.253.118.138
            172.253.118.102
            172.253.118.101
            172.253.118.113
            172.253.118.139
            172.253.118.100
            2404:6800:4003:c11::8a
            2404:6800:4003:c11::71
            2404:6800:4003:c11::64
            2404:6800:4003:c11::8b


# resolvectl query duckduckgo.com
duckduckgo.com: 20.43.161.105

-- Information acquired via protocol DNS in 54.3ms.
-- Data is authenticated: no; Data was acquired via local or encrypted transport: no
-- Data from: network