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

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

 

 

Monday, June 3, 2024

Android java: request multiple permission READ_EXTERNAL_STORAGE & WRITE_EXTERNAL_STORAGE

Minimum API 24 (Android 7.0) 

Note:

  • Beginning with Android 4.4 (API level 19) it's no longer necessary for your app to request the WRITE_EXTERNAL_STORAGE permission to write to its own application-specific directories on external storage, which are provided by getExternalFilesDir(). However, the permission is required for API level 18 and lower. Example:
    File extDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
  • If the permission is a runtime permission or special permission, and if your app is installed on a device that runs Android 6.0 (API level 23) or higher, you must request the runtime permission or special permission yourself.
  • On devices that run Android 4.4 (API level 19) and higher, your app can interact with a documents provider, including external storage volumes and cloud-based storage, using the Storage Access Framework. This framework allows users to interact with a system picker to choose a documents provider and select specific documents and other files for your app to create, open, or modify.
  • To support media file access on devices that run Android 9 (API level 28) or lower, declare the READ_EXTERNAL_STORAGE permission and set the maxSdkVersion to 28. See reference 1.
  • If your app targets Android 10 (API level 29) or lower, you can temporarily opt out of scoped storage in your production app. If you target Android 10, however, you need to set the value of requestLegacyExternalStorage to true in your app's manifest file.

AndroidManifest.xml

...
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"
        android:maxSdkVersion="28"
        />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
        android:maxSdkVersion="28"
        />
...
    <!-- This attribute is "false" by default on apps targeting Android 10. -->
    <!-- android:requestLegacyExternalStorage="true" -->
    <application
        android:requestLegacyExternalStorage="true"
...

MainActivity.java

...
import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
...
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //EdgeToEdge.enable(this);
        setContentView(R.layout.activity_main);

        // android:maxSdkVersion="28" =  Build.VERSION_CODES.P
        if (android.os.Build.VERSION.SDK_INT <= Build.VERSION_CODES.P) {
            checkMyPermission();
        }
...    int MY_CODE_REQUEST = 123;
    /*
     * 1. check permission
     */
    private void checkMyPermission() {
        // Build.VERSION.SDK_INT >= 23
        // https://riptutorial.com/android/example/23932/multiple-runtime-permissions-from-same-permission-groups
        ArrayList<String> sPermissionRequest = new ArrayList<>();
        int myRead = ContextCompat.checkSelfPermission(getApplicationContext()
                , READ_EXTERNAL_STORAGE);
        int myWrite = ContextCompat.checkSelfPermission(getApplicationContext()
                , WRITE_EXTERNAL_STORAGE);
        if (myRead != PackageManager.PERMISSION_GRANTED) {
            sPermissionRequest.add(getString(R.string.s_permission_read_storage));
        }
        if (myWrite != PackageManager.PERMISSION_GRANTED) {
            sPermissionRequest.add(getString(R.string.s_permission_write_storage));
        }

        if (sPermissionRequest.size()>0) {
            // NOT Granted
            String[] sPermissions = new String[sPermissionRequest.size()];
            for (int i=0;i<sPermissionRequest.size();i++) {
                sPermissions[i]=sPermissionRequest.get(i);
            }
            //sLog.e("dedetok", "sPermissionRequest.size()>0 size "+sPermissions.length); // debug
            requestPermissions(sPermissions, MY_CODE_REQUEST);
        }
    }

    /*
     * 2. receive permission status
     */
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);

        if (requestCode==MY_CODE_REQUEST) {

            if (permissions.length>0) {
                ArrayList<String> myPermission = new ArrayList<>();
                for (int i=0;i<permissions.length;i++) {
                    //Log.e("dedetok", permissions[i]+" "+grantResults[i]); // debug
                    if (permissions[i].equals(getString(R.string.s_permission_read_storage)) &&
                            grantResults[i]!=PackageManager.PERMISSION_GRANTED) {
                        myPermission.add(READ_EXTERNAL_STORAGE);
                    }
                    if (permissions[i].equals(getString(R.string.s_permission_write_storage)) &&
                            grantResults[i]!=PackageManager.PERMISSION_GRANTED) {
                        myPermission.add(WRITE_EXTERNAL_STORAGE);
                    }
                }
                // Not granted, Request permissions on runtime

                String[] sRequestPermission = new String[myPermission.size()];
                for (int i=0;i<myPermission.size();i++) {
                    sRequestPermission[i] = myPermission.get(i);
                }

                //Log.e("dedetok", "requestCode==MY_CODE_REQUEST "+sRequestPermission.length); // debug
                requestPermissionLauncher.launch(sRequestPermission);
            }
        }
    }

    /*
     * 3. callback user permission
     * Register the permissions callback, which handles the user's response to the
     * system permissions dialog. Save the return value, an instance of
     * ActivityResultLauncher, as an instance variable.
     */
    private final ActivityResultLauncher<String[] > requestPermissionLauncher =
            registerForActivityResult(new ActivityResultContracts.RequestMultiplePermissions()
                    , new ActivityResultCallback() {
                        @Override
                        public void onActivityResult(Object objMap) {
                            //Log.e("dedetok", "onActivityResult "+o.toString()); // debug
                            if (objMap instanceof Map) {
                                StringBuilder mySB = new StringBuilder();
                                Map<String,Boolean> myMapPermission = (Map<String,Boolean>) objMap;
                                myMapPermission.forEach((permissionKey, permissionBoolean)->{
                                    //Log.e("dedetok", permissionKey+" "+READ_EXTERNAL_STORAGE+" "+permissionBoolean); // debug
                                    if (permissionKey.equals(READ_EXTERNAL_STORAGE) && !permissionBoolean) {
                                        mySB.append(READ_EXTERNAL_STORAGE+" ");
                                    }
                                    if (permissionKey.equals(WRITE_EXTERNAL_STORAGE) && !permissionBoolean) {
                                        mySB.append(WRITE_EXTERNAL_STORAGE+" ");
                                    }
                                });
                                //Log.e("dedetok", "mySB "+mySB.toString()); // debug
                                if (mySB.length()>0) {
                                    updateStatus(mySB.toString());
                                }
                            }
                        }
                    });

 References:

  1. https://developer.android.com/training/data-storage/shared/documents-files
  2. https://developer.android.com/training/permissions/declaring
  3. https://developer.android.com/guide/topics/manifest/uses-permission-element
  4. https://stackoverflow.com/questions/3093365/how-can-i-check-the-system-version-of-android
  5. https://developer.android.com/training/data-storage/use-cases

Friday, May 24, 2024

Android Java: spinner in fragment

layout_fragment_me.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.LinearLayoutCompat
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Fragment"
        android:textSize="38sp"
        />
    <Spinner
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/my_spinner"
        android:minHeight="50dp"
        />

    <androidx.appcompat.widget.AppCompatButton
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="HELLO BUTTON"
        />
</androidx.appcompat.widget.LinearLayoutCompat> 

activity_main.xml

<?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"
    >

    <androidx.fragment.app.FragmentContainerView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/fragment_view_me"
        />
    <androidx.appcompat.widget.AppCompatTextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Main Activity"
        android:textSize="30dp"
        />
</androidx.appcompat.widget.LinearLayoutCompat>

MyData.java

package com.dedetok.tutorialcustomdropdown;

public class MyData {
    public String name, phone;

    @Override
    public String toString() {
        return name+" "+phone;
    }
}

FragmentMe.java

package com.dedetok.tutorialcustomdropdown;

import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Spinner;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;

import java.util.ArrayList;

public class FragmentMe extends Fragment {

    ArrayList<MyData> arrayList = new ArrayList<>();

    public FragmentMe() {
        super(R.layout.layout_fragment_me);
        Log.e("dedetok", "Create Fragment ME"); // debug
    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        init();
        Log.e("dedetok", "size "+arrayList.size()); // debug
        Spinner mySpinner = view.findViewById(R.id.my_spinner);
        ArrayAdapter<MyData> arrayAdapter = new ArrayAdapter<>(getContext(), android.R.layout.simple_spinner_dropdown_item, arrayList);
        Log.e("dedetok", "setAdapter"); // debug
        mySpinner.setAdapter(arrayAdapter);
        mySpinner.setOnItemSelectedListener(mySpinnerListener);

    }

    AdapterView.OnItemSelectedListener mySpinnerListener =
            new AdapterView.OnItemSelectedListener() {

                @Override
                public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
                    if (parent.getItemAtPosition(pos) instanceof MyData) {
                        MyData myData = (MyData) parent.getItemAtPosition(pos);
                        // TODO
                    }
                }

                @Override
                public void onNothingSelected(AdapterView<?> adapterView) {
                    // Do nothing
                }
            };
    private void init() {
        MyData myData = new MyData();
        myData.name = "aaaa";
        myData.phone = "1111";
        arrayList.add(myData);
        myData = new MyData();
        myData.name = "bbbb";
        myData.phone = "2222";
        arrayList.add(myData);
        myData = new MyData();
        myData.name = "ccccc";
        myData.phone = "2233322";
        arrayList.add(myData);
        myData = new MyData();
        myData.name = "4ddddd";
        myData.phone = "444444";
        arrayList.add(myData);
    }
}

MainActivity.java

package com.dedetok.tutorialcustomdropdown;

import android.os.Bundle;

import androidx.activity.EdgeToEdge;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
import androidx.fragment.app.FragmentTransaction;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);


        setContentView(R.layout.activity_main);
        FragmentTransaction transaction = getSupportFragmentManager()
                .beginTransaction();
        FragmentMe fragment = new FragmentMe();
        transaction.setReorderingAllowed(true);
        transaction.add(R.id.fragment_view_me, fragment);
        transaction.commit();
    }
}