Friday, May 31, 2024

Privacy Policy for Event Presensi (com.dedetok.eventpresensi)


 


Sample Data (Copy to any spreadsheet and save as csv)

id_member name_member
100000000001 Rudolf Diesel
100000000002 Albert Einstein
100000000003 Alexander Graham Bell
100000000004 James Watt
100000000005 Alessandro Volta
100000000006 Thomas Alva Edison
100000000007 Samuel F. B. Morse
100000000008 Michael Faraday

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

Wednesday, May 15, 2024

Android Java: open activity for result to pick up / choose a file in Shared Folder - Download /storage/emulated/0/Download

Note:

Moving from startActivityForResult to ActivityResultLauncher to pickup file in Shared Folder - Download /storage/emulated/0/Download

Minimum Android 7 API 24 Targeted SDK Android 24 API 34

build.gradle.kts (Module :app)

plugins {
    alias(libs.plugins.android.application)
}

android {
    namespace = "com.dedetok.tutorialsharedfolder"
    compileSdk = 34

    defaultConfig {
        applicationId = "com.dedetok.tutorialsharedfolder"
        minSdk = 24
        targetSdk = 34
        versionCode = 1
        versionName = "1.0"

        testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
    }

    buildTypes {
        release {
            isMinifyEnabled = false
            proguardFiles(
                getDefaultProguardFile("proguard-android-optimize.txt"),
                "proguard-rules.pro"
            )
        }
    }
    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_1_8
        targetCompatibility = JavaVersion.VERSION_1_8
    }
}

dependencies {

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

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"
        android:maxSdkVersion="29"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
        android:maxSdkVersion="29"/>
    <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>

    <application
        android:requestLegacyExternalStorage="true"
        android:allowBackup="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.TutorialSharedFolder"
        tools:targetApi="31">

        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

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.constraintlayout.widget.ConstraintLayout>

MainActivity.java

package com.dedetok.tutorialsharedfolder;

import android.Manifest;
import android.app.Activity;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import androidx.activity.EdgeToEdge;
import androidx.activity.result.ActivityResult;
import androidx.activity.result.ActivityResultCallback;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.ContextCompat;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;

import android.provider.DocumentsContract;

public class MainActivity extends AppCompatActivity {

    /*
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"
        android:maxSdkVersion="29"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
        android:maxSdkVersion="29"/>
    <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
    <application
        android:requestLegacyExternalStorage="true"

    /storage/emulated/0/Download

    MediaStore.Downloads (/storage/emulated/0/Download) Android 10 (API level 29) and higher,
     */


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        EdgeToEdge.enable(this);
        setContentView(R.layout.activity_main);

        /*
         * check perrmission
         */
        boolean isPermitted;
        String myPermissionRequired = android.Manifest.permission.READ_EXTERNAL_STORAGE;
        isPermitted = myCheckPermission(this, myPermissionRequired);
        Log.e("dedetok", "READ_EXTERNAL_STORAGE: "+isPermitted);

        myPermissionRequired = android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
        isPermitted = myCheckPermission(this, myPermissionRequired);
        Log.e("dedetok", "WRITE_EXTERNAL_STORAGE: "+isPermitted);
        myPermissionRequired = Manifest.permission.MANAGE_EXTERNAL_STORAGE;
        isPermitted = myCheckPermission(this, myPermissionRequired);
        Log.e("dedetok", "MANAGE_EXTERNAL_STORAGE: "+isPermitted);

        /*
         * root Environment.getExternalStorageDirectory() -> /storage/emulated/0
         */
        // get root directory path NOT USED
        File fExternalStorage = Environment.getExternalStorageDirectory();
        String sFExternalStorage = fExternalStorage.getPath();
        //String fsFExternalStorage = sFExternalStorage+File.separator+sFilename;
        Log.e("dedetok", "Environment.getExternalStorageDirectory() "+sFExternalStorage); //debug

        /*
         * Access file in /storage/emulated/0/Download
         * Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) ->
         *          /storage/emulated/0/Download
         */
        // get Download directory path NOT USED IN PICK FILE BUT USED IN PRINT FILE
        File extDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
        String dirPath = extDir.getPath();
        Log.e("dedetok", "getExternalStoragePublicDirectory "+dirPath); //debug

        /*
         * Select file in Download Folder
         */
        //getFileURI(); // OLD WAT Deprecated
        getFileURINew(); // New Way using system dialog to select file

        /*
         * writing to Download Folder
         */
        String sFileOutput = extDir+File.separator+"helloworld.txt";
        File fOutput = new File(sFileOutput);
        try {
            PrintWriter myPW = new PrintWriter(fOutput);
            myPW.println("Hello World");
            myPW.println("this is a test");
            myPW.flush();
            myPW.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace(); // debug
        }


    }

    /*
     * self check permission function
     */
    private boolean myCheckPermission(Context appContext, String sPermission) {
        return (ContextCompat.checkSelfPermission(appContext, sPermission)
                == PackageManager.PERMISSION_GRANTED);
        // or
        // return (PermissionChecker.checkSelfPermission(appContext, sPermission)
        //        == PermissionChecker.PERMISSION_GRANTED);
    }

    ///////////// THIS IS PART OF DEPRECATED SECTION START /////////////
    /*
     * get result
     */
    @Override
    protected void onActivityResult(int requestCode, int resultCode,
                                    Intent resultData) {
        super.onActivityResult(requestCode, resultCode, resultData);
        if (requestCode == MY_ID_PICK_FILE
                && resultCode == Activity.RESULT_OK) {
            // The result data contains a URI for the document or directory that
            // the user selected.
            Uri uri;
            if (resultData != null) {
                uri = resultData.getData();
                // Perform operations on the document using its URI.
                Log.e("dedetok", "Result"); // debug
                if (uri!=null) {

                    Log.e("dedetok", "Result uri: "+uri.getPath()); // debug
                    openMyFile(uri);
                }
            }
        }

    }
    private static final int MY_ID_PICK_FILE = 1; // any number
    private static final String mimeTypeFilter = "text/csv";
    /*
     * https://developer.android.com/training/data-storage/shared/documents-files
     * https://stackoverflow.com/questions/71667342/how-to-allow-selection-of-csv-in-a-file-chooser-intent-in-android
     * Deprecated startActivityForResult
     */
    private void getFileURI() {
        String[] myMime = {"*/*",
                "text/plain",
                "application/csv",
                "application/vnd.ms-excel",
                "application/excel",
                "application/x-excel",
                "application/x-msexcel"
        };
        Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT); // MUST
        intent.addCategory(Intent.CATEGORY_OPENABLE); // MUST
        intent.setType(mimeTypeFilter);

        // Optionally, specify a URI for the file that should appear in the
        // system file picker when it loads.
        intent.putExtra(Intent.EXTRA_MIME_TYPES, myMime);

        startActivityForResult(intent, MY_ID_PICK_FILE);
    }
    ///////////// THIS IS PART OF DEPRECATED SECTION END /////////////

    ///////////// THIS PART OF NEW WAY START /////////////
    /*
     * https://developer.android.com/training/basics/intents/result
     */
    private void getFileURINew() {
        String[] myMime = {"*/*",
                "text/plain",
                "application/csv",
                "application/vnd.ms-excel",
                "application/excel",
                "application/x-excel",
                "application/x-msexcel"
        };
        Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT); // MUST
        intent.addCategory(Intent.CATEGORY_OPENABLE); // MUST
        intent.setType(mimeTypeFilter);

        // Optionally, specify a URI for the file that should appear in the
        // system file picker when it loads.
        intent.putExtra(Intent.EXTRA_MIME_TYPES, myMime);

        mGetContent.launch(intent);
    }
    // ActivityResultCallback
    ActivityResultCallback<ActivityResult> myActivityResult = new ActivityResultCallback<ActivityResult>() {
        @Override
        public void onActivityResult(ActivityResult aResult) {
            if (aResult.getResultCode()==RESULT_OK) {
                Intent iData = aResult.getData();
                Uri uriData = iData.getData();
                Log.e("dedetok", "new "+uriData.getPath());

            }

        }
    };
    // ActivityResultContracts
    ActivityResultContracts.StartActivityForResult myARC = new ActivityResultContracts.StartActivityForResult();
    // ActivityResultLauncher
    ActivityResultLauncher<Intent> mGetContent = registerForActivityResult(
        myARC,
        myActivityResult);
    ///////////// THIS PART OF NEW WAY END /////////////

    ///////////// SUPPORTING FUNCTION /////////////
    /*
     * Open File after receive from system pick up
     */
    private void openMyFile(Uri uriMyFile) {
        //getFileURI(); // crash
        StringBuilder stringBuilder = new StringBuilder();
        if (isVirtualFile(uriMyFile)) {
            Log.e("dedetok","It is Virual"); // debug
            ContentResolver resolver = getContentResolver();

            String[] openableMimeTypes = resolver.getStreamTypes(uriMyFile, mimeTypeFilter);

            if (openableMimeTypes != null ||
                    openableMimeTypes.length > 0) {

                try {
                    InputStream inputStream = resolver
                            .openTypedAssetFileDescriptor(uriMyFile, openableMimeTypes[0], null)
                            .createInputStream();
                    BufferedReader reader = new BufferedReader(
                            new InputStreamReader(inputStream));
                    String line;
                    while ((line = reader.readLine()) != null) {
                        stringBuilder.append(line);
                    }
                } catch (IOException e) {
                    e.printStackTrace(); // debug
                }
            }

        } else {
            try {
                InputStream inputStream =
                         getContentResolver().openInputStream(uriMyFile);
                BufferedReader reader = new BufferedReader(
                         new InputStreamReader(inputStream));
                String line;
                while ((line = reader.readLine()) != null) {
                    stringBuilder.append(line);
                }
            } catch (IOException e) {
                e.printStackTrace(); // debug
            }
        }
        Log.e("dedetok",stringBuilder.toString());
    }

    /*
     * check if file receive is virtual
     * Android 7.0 (API level 24) and higher
     *https://developer.android.com/training/data-storage/shared/documents-files
     */
    private boolean isVirtualFile(Uri uri) {
        if (!DocumentsContract.isDocumentUri(this, uri)) {
            return false;
        }

        Cursor cursor = getContentResolver().query(
                uri,
                new String[] { DocumentsContract.Document.COLUMN_FLAGS },
                null, null, null);

        int flags = 0;
        if (cursor.moveToFirst()) {
            flags = cursor.getInt(0);
        }
        cursor.close();

        return (flags & DocumentsContract.Document.FLAG_VIRTUAL_DOCUMENT) != 0;
    }

}

References:

  • https://developer.android.com/training/basics/intents/result
  • https://devofandroid.blogspot.com/2022/09/get-result-from-another-activity-using.html
  • https://medium.com/@steves2001/moving-from-android-startactivityforresult-to-registerforactivityresult-76ca04044ff1
  • https://www.geeksforgeeks.org/how-to-use-activityforresultluncher-as-startactivityforresult-is-deprecated-in-android/


Thursday, May 2, 2024

Ukuran ban dan merek di Indonesia

Ban 185/60 R14

  1. Bridgestone Turanza 185/60 R14
  2. GT Radial Eco 185/60 R14
  3. GT Radial Ecotec 185/60 R14
  4. Dunlop SP Touring R1 185/60 R14
  5. Goodyear Assurance Triplemax 185/60 R14
  6. Goodyear Assurance Triplemax2 185/60 R14
  7. Hankook Kinergy Eco K435 185/60 R14 
  8. Achilles 868 All Seasons - 185/60 R14 82H
  9. Achilles 122 185/60 R14
  10. Accelera Epsilon 185/60 R14 1 arah
  11. BFGoodrich Advantage Touring 185 60 R14 
  12. Falken Sincera SN832i 185/60 R14 
  13. Forceum D 600 185/60 R14
  14. Michelin Energy XM2+ 185/60 R14
  15. Michelin Energy XM2 185/60 R14 
  16. Toyo Tires NanoEnergy 3 (TTM) 185/60 R14
Ban 175/65 R14 *
  1. Bridgestone Ecopia EP 150 175/65 R14
  2. Bridgestone Turanza 175/65 R14
  3. Bridgestone Techno 175/65 R14 
  4. GT Radial Champiro Ecotec 175/65 R14 
  5. GT Radial Champiro Eco 175/65 R14 
  6. Dunlop Enasave EC300+ 175/65 R14
  7. Dunlop SP Touring R1 175/65 R14
  8. Goodyear Assurance Duraplus 2 175/65 R14
  9. Goodyear Assurance Duraplus 175/65 R14 
  10. Goodyear Assurance TripleMax 175/65 R14
  11. Hankook Kinergy Eco2 175/65 R14 
  12. Hankook Kinergy Eco 175/65 R14 
  13. Hankook Optiomo H724 175/65 R14
  14. Achilles All Seasons 868 175/65 R14
  15. Achilles 122 - 175/65 R14 82H
  16. Achilles Platinum 175/65 R14
  17. Accelera Eco Plush 175/65 R14
  18. BFGoodrich Advantage Touring 175/65 R14
  19. Falken Sincera SN832i 175/65 R14
  20. Forceum Ecosa 175/65 R14
  21. Forceum N 300 175/65 R14
  22. Michelin Energy XM2+ 175/65 R14
  23. Michelin Energy XM2 175/65 R14
  24. Toyo Tires NanoEnergy 3 (TTM) 175/65 R14