Showing posts with label Android. Show all posts
Showing posts with label Android. Show all posts

Thursday, April 22, 2021

Http/1.1 vs Http/2 vs Http/3 on Android

General Differences

As the version upgrades, the new versions support extra compression techniques to increase the network speed.


HTTP/1.1

The most base HTTP version.


HTTP/2

This blog explains well in detail.

Date: Since 2015

Speed improvements through:
- Request multiplexing: Multiple requests for data in parallel over a single TCP connection
- Header compression.
- Binary protocol


HTTP/3

This blog explains well in detail.

Date: Since 2019

QUIC is a network layer protocol implemented over UDP. Simply put, QUIC is an improvement over TCP. On top of TCP, QUIC also provides:
  • Dramatically reduced connection establishment time
  • Improved congestion control
  • Multiplexing without head of line blocking
  • Forward error correction
  • Connection migration



Friday, October 23, 2020

How to detect whether the Notification is turned off by the user or not

Users can turn off the notification from the Android Settings.

Here's how to detect it programmatically.


For Android O+, also need to check the channel you're looking for is turned off.


private fun isNotificationEnabled(context: Context, channelId: String): Boolean {
try {
var enabled = NotificationManagerCompat.from(context).areNotificationsEnabled()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O &&
isChannelBlocked(context, channelId)) {
enabled = false
}
return enabled
} catch (e: Exception) {
}
return false
}


@TargetApi(Build.VERSION_CODES.O)
@RequiresApi(Build.VERSION_CODES.M)
private fun isChannelBlocked(context: Context, channelId: String): Boolean {
try {
val manager = context.getSystemService(NotificationManager::class.java)
val channel = manager.getNotificationChannel(channelId)
return channel != null && channel?.importance == NotificationManager.IMPORTANCE_NONE
} catch (e: Exception) {
}
return false
}

 

Tuesday, August 11, 2015

Android: Detect 7" or 10" tablet programmatically (get smallest width dp)


Some other solutions out there are outdated.

This solution is when you are targeting API 13+. (You should now be targeting 14+ - written in 2015.08.11)

     int smallestDp = getResources().getConfiguration().smallestScreenWidthDp;  
     if(smallestDp >= 600 && smallestDp < 720) { // 7" ~ <10"  
     }  
     else if(smallestDp >= 720) { // 10"+  
     }  



Tuesday, June 9, 2015

Converting array to list in Android


Simple solution:

public void arrayToList() {

    String sArray[] = new String[]{"A", "B", "C"};
    // This will work as is. However, if you try to add another 
    // String then you will get java.lang.UnsupportedOperationException    
    List lList = Arrays.asList(sArray);

}

However, you can't add another value if you just use asList().


Solution: use new ArrayList()
public void arrayToList() {

    String sArray[] = new String[]{"A", "B", "C"};
    List lList = new ArrayList(Arrays.asList(sArray));        // now add(String) works    lList.add("D");}



Friday, November 21, 2014

Android: Custom toast example (different text size, different background color)


toast.getView().setBackgroundColor() will change the background color.
toast.getView().findViewById(android.R.id.message).setTextColor() will change the text color.

    private void makeCustomToast(String message) {
        Toast toast = Toast.makeText(mContext, message, Toast.LENGTH_SHORT);
        TextView v = (TextView) toast.getView().findViewById(android.R.id.message);
        toast.getView().setBackgroundColor(mContext.getResources().getColor(R.color.blue));
        v.setTextColor(mContext.getResources().getColor(R.color.white));
        toast.show();
    }

Android: Get app version programmatically example


Get version name & version code

String sVersionName;
int iVersionCode;
try {
    PackageInfo pInfo = getPackageManager().getPackageInfo(getPackageName(), 0);
    sVersionName = pInfo.versionName;
    iVersionCode = pInfo.versionCode;
} catch (PackageManager.NameNotFoundException e) {
    sVersionName = "Unknown";
    iVersionCode = 1;
}

Version name & version code is from what you have defined in AndroidManifest.xml

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.example1"
    android:versionCode="14"
    android:versionName="1.2.2">





Friday, September 26, 2014

Support Chinese Translation (Support Traditional & Simplified) but also Hong Kong

Up until now I was using:

"values-zh-rCN" -> Simplified Chinese
"values-zh-rTW" -> Traditional Chinese

I thought I covered entire Chinese. I was wrong!
There's 'zh-rHK' for Hong Kong.

Since I didn't cover Hong Kong Traditional Chinese, it showed default language which is English.

Hong Kong Traditional Chinese is same as Taiwan Traditional Chinese.
So, you should change to:

"values-zh-rCN" -> Simplified Chinese
"values-zh" -> Traditional Chinese (Covering Taiwan, Hong Kong, Macau, and other places)

Why I didn't add 'zh-rHK'?
Because if there is some other Chinese languages that I wasn't aware, then values-zh should cover them all.

Thursday, May 1, 2014

[Android] How to code 'android:background="?android:attr/selectableItemBackground"' programmatically example

You can't (umm.. there is but hard). So there's a work around.

layout\textview_selectable.xml
 <TextView xmlns:android="http://schemas.android.com/apk/res/android"  
   android:background="?android:attr/selectableItemBackground"
   android:layout_width="match_parent"  
   android:layout_height="wrap_content"  
   />  

then in your code:
 TextView tv = (TextView)getLayoutInflater().inflate(R.layout.textview_selectable, null);

[Android] Set style programatically example

You can't. So there's a work around.

layout\textview_mystyle.xml
 <TextView xmlns:android="http://schemas.android.com/apk/res/android"  
   style="@style/myStyleText"  
   android:layout_width="match_parent"  
   android:layout_height="wrap_content"  
   />  

then in your code:
 TextView tv = (TextView)getLayoutInflater().inflate(R.layout.textview_mystyle, null);

Wednesday, April 30, 2014

[Android] How to send email(Gmail) programmatically without launching a third party app (new intent)

First you need following "javamail-android" libraries: (download)
  • additionnal.jar 
  • mail.jar
  • activation.jar

Copy them to \libs folder and add copied jars to your project library.

You need following permissions:
   <uses-permission android:name="android.permission.GET_ACCOUNTS" />  
   <uses-permission android:name="android.permission.INTERNET" />  
   <uses-permission android:name="android.permission.USE_CREDENTIALS" />  

OAuth2Authenticator.java:
   
 import android.accounts.Account;  
 import android.accounts.AccountManager;  
 import android.accounts.AccountManagerCallback;  
 import android.accounts.AccountManagerFuture;  
 import android.app.Activity;  
 import android.os.AsyncTask;  
 import android.os.Bundle;  
 import android.util.Log;  
   
 import com.sun.mail.smtp.SMTPTransport;  
 import com.sun.mail.util.BASE64EncoderStream;  
   
 import java.util.Properties;  
   
 import javax.activation.DataHandler;  
 import javax.mail.Message;  
 import javax.mail.Session;  
 import javax.mail.URLName;  
 import javax.mail.internet.InternetAddress;  
 import javax.mail.internet.MimeMessage;  
 import javax.mail.util.ByteArrayDataSource;  
   
   
 public class OAuth2Authenticator {  
   
   private static Session mSession;  
   
   private AccountManager mAccountManager;  
   private String mToken;  
   private Account mAccount = null;  
   private Activity mActivity;  
   private static String TEST_ACCOUNT_EMAIL = "(your_account_that_is_added_to_Android_device)@gmail.com";  
   
   public OAuth2Authenticator(Activity activity) {  
     mActivity = activity;  
     mAccountManager = AccountManager.get(mActivity);  
   
     Account[] accounts = mAccountManager.getAccounts();  
   
     // For this tutorial, we manually set the email account(TEST_ACCOUNT_EMAIL). However, you should create some kind of UI for users to select the Gmail account  
     for (Account a : accounts) {  
       if (a.name.equals(TEST_ACCOUNT_EMAIL) && a.type.equals("com.google")) {  
         mAccount = a;  
       }  
     }  
     if (mAccount != null) {  
       AccountManagerFuture<Bundle> future = mAccountManager.getAuthToken(mAccount, "oauth2:https://mail.google.com/", null, mActivity, new OnTokenAcquired(), null);  
     }  
   
   }  
   
   private class OnTokenAcquired implements AccountManagerCallback<Bundle> {  
     @Override  
     public void run(AccountManagerFuture<Bundle> result) {  
       try {  
         Bundle bundle = result.getResult();  
         mToken = bundle.getString(AccountManager.KEY_AUTHTOKEN);  
         new SendMailTask().execute();  
       } catch (Exception e) {  
         Log.e("OnTokenAcquired", e.getMessage());  
       }  
     }  
   }  
   
   private class SendMailTask extends AsyncTask<Void, Void, Void> {  
   
     @Override  
     protected Void doInBackground(Void... params) {  
       try {  
         sendMail("subject", "body message", TEST_ACCOUNT_EMAIL, mToken, "(recipient_address)@(somemail).com");  
       } catch (Exception e) {  
         Log.e("SendMailTask", "error:" + e.getMessage());  
       }  
       return null;  
     }  
   }  
   
   private SMTPTransport connectToSmtp(String host, int port, String userEmail,  
                     String oauthToken, boolean debug) throws Exception {  
   
     Properties props = new Properties();  
     props.put("mail.smtp.starttls.enable", "true");  
     props.put("mail.smtp.starttls.required", "true");  
     props.put("mail.smtp.sasl.enable", "false");  
     mSession = Session.getInstance(props);  
     mSession.setDebug(debug);  
     final URLName unusedUrlName = null;  
     SMTPTransport transport = new SMTPTransport(mSession, unusedUrlName);  
     // If the password is non-null, SMTP tries to do AUTH LOGIN.  
     final String emptyPassword = null;  
     transport.connect(host, port, userEmail, emptyPassword);  
     byte[] response = String.format("user=%s\1auth=Bearer %s\1\1", userEmail, oauthToken).getBytes();  
     response = BASE64EncoderStream.encode(response);  
     transport.issueCommand("AUTH XOAUTH2 " + new String(response), 235);  
     return transport;  
   }  
   
   public synchronized void sendMail(String subject, String body, String user,  
                    String oauthToken, String recipients) {  
     try {  
   
       SMTPTransport smtpTransport = connectToSmtp("smtp.gmail.com",  
           587,  
           user,  
           oauthToken,  
           true);  
       MimeMessage message = new MimeMessage(mSession);  
       DataHandler handler = new DataHandler(new ByteArrayDataSource(body.getBytes(), "text/plain"));  
       message.setSender(new InternetAddress(user));  
       message.setSubject(subject);  
       message.setDataHandler(handler);  
       if (recipients.indexOf(',') > 0)  
         message.setRecipients(Message.RecipientType.TO, InternetAddress.parse(recipients));  
       else  
         message.setRecipient(Message.RecipientType.TO, new InternetAddress(recipients));  
       smtpTransport.sendMessage(message, message.getAllRecipients());  
     } catch (Exception e) {  
       Log.e("sendMail", e.getMessage());  
     }  
   }  
 }  

MainActivity.java:
 new OAuth2Authenticator(this);  


Friday, April 18, 2014

Android: how to send SMS(text message) programmatically


You need SEND_SMS permission:

Code:
        try {
            SmsManager smsManager = SmsManager.getDefault();
            String sPhoneNumber = "1-222-3333";
            String sMessage = "Hello World";
            smsManager.sendTextMessage(sPhoneNumber, null, sMessage, null, null);
            Toast.makeText(this, "Message has been sent", Toast.LENGTH_LONG).show();
        } catch (Exception e) {
            Toast.makeText(this, "Message send failed", Toast.LENGTH_LONG).show();
        }

Warning: Make sure your app doesn't send SMS without user's knowledge. It will violate the Google's policy and your app will be suspended.

  • Do not send SMS, email, or other messages on behalf of the user without providing the user with the ability to confirm content and intended recipient.


Developer's Guide: What API level should you target for your app? (minSdkVersion)

This is my personal opinion. (Not a correct answer)
(Note: I am writing this on April 18, 2014. Things might be different later)

Please check the latest version distribution dashboard first.

Free app or paid app?
If you are making a paid app, it is OK to target relatively latest versions only. I say version 14 (Android 4.0+) [or version 15 (Android 4.0.3+) since not many devices use version 14 anyways]. There is a big jump from 2.x to 4.x no need an extra work to support 2.x devices when your main income is from the paid app (or in-app-purchase).

Why? I found most paid apps are purchased from the latest devices anyways. People who use older devices are pretty much satisfied with apps they already have and they don't tend to look for paid apps (compared to people who uses the latest devices). I don't make games so I am not sure if above logic applies for games too.

If your income is a free app with ad then you want to cover as much as possible. Still, I believe 2.x devices are not worth it at this time.

Think about testing
You might think the more device support the better. Not always! If your app doesn't work properly on some devices (or some older versions), they will give you bad ratings/reviews and your overall ratings will decrease. One of my apps got more popular when I actually removed the support for older devices for this reason.

Again, this is my personal opinion from my experience.

Wednesday, April 16, 2014

Android: Show notification example


Show notification:

        Intent intent = new Intent(context, ExampleReceiver.class);
        PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
        NotificationManager notificationManager = (NotificationManager) context.getSystemService(context.NOTIFICATION_SERVICE);
        Notification n;
        Bitmap bm = BitmapFactory.decodeResource(context.getResources(), R.drawable.ic_launcher);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
            n = new Notification.Builder(context)
                    .setContentTitle("title")
                    .setContentText("Short message\nContent message")
                    .setTicker("ticker message")
                    .setSmallIcon(R.drawable.notification_icon)
                    .setLargeIcon(bm)
                    .setStyle(new Notification.BigTextStyle().bigText("Long message.\nTesting..Testing..\nlooooooooooooooooon message"))
                    .setContentIntent(paramIntent)
                    .setAutoCancel(true).build();
        } else {
            n = new Notification.Builder(context)
                    .setContentTitle("title")
                    .setContentText("Short message\nContent message")
                    .setTicker("ticker message")
                    .setSmallIcon(R.drawable.notification_icon)
                    .setLargeIcon(bm)
                    .setContentIntent(paramIntent)
                    .setAutoCancel(true).getNotification();
        }
        n.flags = n.flags | Notification.FLAG_NO_CLEAR;
        notificationManager.notify(0, n);


Show only the ticker and make it go disappear:

        Intent intent = new Intent(context, ExampleReceiver.class);
        PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
        NotificationManager notificationManager = (NotificationManager) context.getSystemService(context.NOTIFICATION_SERVICE);
        Notification n;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
            n = new Notification.Builder(context)
                    .setTicker("ticker message")
                    .setSmallIcon(R.drawable.notification_icon)
                    .setAutoCancel(true)
                    .build();
        } else {
            n = new Notification.Builder(context)
                    .setTicker("ticker message")
                    .setSmallIcon(R.drawable.notification_icon)
                    .setAutoCancel(true)
                    .getNotification();
        }
        notificationManager.notify(0, n);
        notificationManager.cancel(0);


Monday, April 14, 2014

How to outsource/freelance Android app icon design for a cheap price?

You make apps and you have a terrible icon so no one downloads your app. Here's a solution:

Here's what I've learned (so far).

Fiverr
The cheapest place to do is fiverr.
Watch out! Not everything is $5.
They make you add this and that feature for extra $5~$20. But if you search carefully, some designers satisfies all your needs in $5.

Warning: Make sure you provide EVERYTHING you want your icon to be like. Don't expect them to read your mind and receive an awesome icon. Sometimes you have no idea what kind of icon is suitable. Even so, do some research because most likely they don't spend time to do research either. You end up, wasting your time and their time, and your money. (Been there, done that).

Provide either:

  • A pencil sketch of expected icon (take a photo and send to the designer)
  • A link or screenshot of an existing icon (maybe some other competitor icon) and tell them you want this style.
  • A detail description. (Color of the icon, add a shadow effect or flat icon, etc etc)
You still have a chance to go back and forth and request modification until you're satisfied but you should provide detail expectation ahead of time so that you don't waste the designer's time.

In my experience, when I requested for an awesome icon and explained what my app does, they made me a crappy icon. I had to provide EXACTLY what to do, they did a good job.

It seems you pay hourly, I haven't done it.

You provide a description and multiple designers make an icon for you. You simply pick the best one and give the money to the winner. The benefit is that you can compare and pick the best icon that you like. Not cheap so I haven't done it.

Use license-free free icons. See my 'Where to get a free Android icons?'



Please add a comment if you know other places.

Where to get a free Android icons?

Here's the list of places you can search for the free icons.
Make sure you set filter for "Commercial free" if your app is 'paid' app or has an 'ad' (you make some sort of profit)

http://www.iconarchive.com/
https://www.iconfinder.com/
http://findicons.com/
http://iconizer.net/en/free_icons

You can also search 'Google image' with "(search word) + icon" and set 'Labeled for reuse' filter.



Please add a comment if you know other places.


Wednesday, March 27, 2013

Android: How to compare Drawables


Answer:

  drawable1.getConstantState().equals(drawable2.getConstantState());

It doesn't compare actual data (bytes of images) so it is fast and memory efficient.

Monday, March 25, 2013

Android: How to use Android default font size example

Small:
<style name="DefaultMedium">

<item name="android:textAppearance">?android:attr/textAppearanceSmall</item>

</style>


Medium:

<style name="DefaultMedium">

<item name="android:textAppearance">?android:attr/textAppearanceMedium</item>

</style>

Large:

<style name="DefaultMedium">

<item name="android:textAppearance">?android:attr/textAppearanceLarge</item>

</style>

Reference: Android source code

Android Styles.xml
https://github.com/android/platform_frameworks_base/blob/master/core/res/res/values/styles.xml

Android Res files
https://github.com/android/platform_frameworks_base/tree/master/core/res/res

Friday, March 22, 2013

Android: Full Screen & No title/action bar example

No Action bar:

this.requestWindowFeature(Window.FEATURE_NO_TITLE);
Caution: this code has to be written BEFORE setContentView(...); or it will crash!

Full Screen:
this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);


@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

this.requestWindowFeature(Window.FEATURE_NO_TITLE);

this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);

setContentView(R.layout.layout_main);

}

Android: Question mark only in strings.xml resource example

Use backslash:

    <string name="quick_question">\?</string>

Thursday, March 21, 2013

Android: Get screen width programmatically example

It returns number in pixel





      @SuppressLint("NewApi")
      private int getScreenWidth() {
            int iMeasuredwidth = 0;
            Point size = new Point();
            WindowManager w = getWindowManager();
            if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2){
                  w.getDefaultDisplay().getSize(size);
                  iMeasuredwidth = size.x;
            }else{
                  Display d = w.getDefaultDisplay();
                  iMeasuredwidth = d.getWidth();
            }
            return iMeasuredwidth;
      }