Blog

removing trailing white space

Sometimes you might want to remove extra white space at the end of a string.

one example is when you have something like this:

public static Spanned fromHtml(String html) {
    Spanned result;
    result = Html.fromHtml(html);
    return result;
}

The problem with the above is that the Html.fromHtml(html) actually appends a “\n\n” at the end of the text. I don’t know why it does that though.

to remove the white space you can do something like this:

source: http://stackoverflow.com/questions/9589381/remove-extra-line-breaks-after-html-fromhtml

/** Trims trailing whitespace. Removes any of these characters:
 * 0009, HORIZONTAL TABULATION
 * 000A, LINE FEED
 * 000B, VERTICAL TABULATION
 * 000C, FORM FEED
 * 000D, CARRIAGE RETURN
 * 001C, FILE SEPARATOR
 * 001D, GROUP SEPARATOR
 * 001E, RECORD SEPARATOR
 * 001F, UNIT SEPARATOR
 * @return "" if source is null, otherwise string with all trailing whitespace removed
 */
public static CharSequence trimTrailingWhitespace(CharSequence source) {

    if(source == null)
        return "";

    int i = source.length();

    // loop back to the first non-whitespace character
    while(--i >= 0 && Character.isWhitespace(source.charAt(i))) {
    }

    return source.subSequence(0, i+1);
}

Standard drawable folder images are considered as mdpi by default

Images that are stored in the Drawables folder are considered as mdpi, this means that when an xxxhdpi device is running the app those images will get scaled up by 3x making them big and causing issues.

Solution: if the images are too big then move them into a bigger drawable density folder and in this way the system will scale them down for lower densities

there is also the drawable-nodpi if you want no scaling but normally you will want scaling (otherwise the real size would be very different across different devices) so it is better to get 1 high res image and put that in the xxhdpi or xxxhdpi folder and let android scale it down on lower res devices.

Suppressing lint on specific line/string in resources xml files

Source: http://stackoverflow.com/questions/23964489/how-to-suppress-lint-on-specific-line-string-in-resources-xml-files

If you want to suppress specific rules in specific strings without suppressing the whole file, you can use annotations.

strings.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>    

    <!--suppress MissingTranslation -->
    <string name="suppress_lint_string">ignore my translation</string>
    ...

</resources>

You can substitute MissingTranslation with any other lint rule.

http://tools.android.com/tips/lint/suppressing-lint-warnings

variables in the local.properties file in android studio

local.properties file

## This file is automatically generated by Android Studio.
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
#
# This file must *NOT* be checked into Version Control Systems,
# as it contains information specific to your local configuration.
#
# Location of the SDK. This is only used by Gradle.
# For customization when using a Version Control System, please read the
# header note.
#Mon Aug 22 10:54:33 BST 2016
sdk.dir=C\:\\Users\\MrDevMonk\\AppData\\Local\\Android\\Sdk
addsuffix=true

and then in the app gradle you can access it using the Properties class

Properties properties = new Properties()
properties.load(project.rootProject.file('local.properties').newDataInputStream())
def addsuffix = properties.getProperty('addsuffix')

and you can also add it in the buildConfigField

buildConfigField "boolean", "ADD_SUFFIX", addsuffix

and from your hava classes you can access it:

BuildConfig.ADD_SUFFIX

Smooth FAB animation with viewpager/tabslider (Based on Material Design Guidelines)

First, you need to have the layout with the floating action button anchored to the ViewPager:

<android.support.design.widget.CoordinatorLayout
    android:id="@+id/main_content"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.design.widget.AppBarLayout
        android:id="@+id/appbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">

        <android.support.v7.widget.Toolbar
            android:id="@+id/action_bar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="?attr/colorPrimary"
            app:layout_scrollFlags="scroll|enterAlways"
            app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/>

        <android.support.design.widget.TabLayout
            android:id="@+id/tabs"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@android:color/white"
            app:tabGravity="center"
            app:tabIndicatorColor="?attr/colorAccent"
            app:tabMode="scrollable"
            app:tabSelectedTextColor="?attr/colorAccent"
            app:tabTextColor="@android:color/black" />

    </android.support.design.widget.AppBarLayout>

    <android.support.v4.view.ViewPager
        android:id="@+id/viewpager"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior" />

     <android.support.design.widget.FloatingActionButton
            android:id="@+id/fab"
            app:layout_anchor="@id/viewpager"
            app:layout_anchorGravity="bottom|right|end"
            android:layout_width="56dp"
            android:layout_height="56dp"
            android:src="@drawable/ic_add_white"
            app:borderWidth="@dimen/fab_border_width"
            app:fabSize="normal" />

</android.support.design.widget.CoordinatorLayout>

Now that you have the FAB anchored to the ViewPager (note: I’ve tried this on a fragment that is a tab in the viewpager; it does not seem to behave properly), add an OnPageChangeListener to your ViewPager like so:

 viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
        @Override
        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
        }

        @Override
        public void onPageSelected(int position) {

            switch (position) {
                case INDEX_OF_TAB_WITH_FAB:
                    fab.show();
                    break;

                default:
                    fab.hide();
                    break;
            }
        }

        @Override
        public void onPageScrollStateChanged(int state) {

        }
    });

The animations for the “pop” and the “shrink” upon switching tabs are handled automatically for you with the new version of the Support Library.

 

Source: Chantell Osejo

Based on material design guidelines

Creating a notification with a PendingIntent and handle opening a not launcher activity directly with a good UX

The below creates a notification that when clicked it opens the DataDetailsActivity.class as a visible screen first and in the back stack it will open the MainActivity. This means that when you press the back button while in the DataDetailsActivity.class the user will be navigated to the MainActivity.class. If the app is already open when the notification is clicked it will clear all its activities from the back stack (this is the result of the FLAG_ACTIVITY_CLEAR_TASK) and then recreate the activity classes that were passed in the intents using the FLAG_ACTIVITY_NEW_TASK to open the activities in a new task.

Eventually, this gives a nice UX when you want to open an activity directly and the launcher activity is not there.

private void createNotification(Data data) {
    // Prepare intent which is triggered if the
    // notification is selected
    Intent intent = new Intent(this, DataDetailsActivity.class);
    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    intent.putExtra(IntentConstants.EXTRA_DATA,data);
    intent.putExtra(IntentConstants.EXTRA_FROM_ALERT_JOB_SERVICE, true);

    Intent backIntent = new Intent(this, MainActivity.class);
    backIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);

    PendingIntent pIntent = PendingIntent.getActivities(this, (int) (System.currentTimeMillis()), new Intent[]{backIntent, intent}, 0);

    // Build notification
    // Actions are just fake
    Notification noti = new Notification.Builder(this)
            .setContentTitle("Alert!! " + sCounter)
            .setContentText(data.getName() + " Alert!").setSmallIcon(R.drawable.ic_launcher)
            .setContentIntent(pIntent)
            .addAction(R.drawable.ic_unfavourite, "Call", pIntent)
            .addAction(R.drawable.ic_favourite, "More", pIntent)
            .addAction(R.mipmap.ic_launcher, "And more", pIntent).build();
    NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
    // hide the notification after its selected
    noti.flags |= Notification.FLAG_AUTO_CANCEL;

    notificationManager.notify(0, noti);

}

EditText takes focus on activity start

Using android:focusableInTouchMode=”true” on the views that you don’t want to take focus automatically. It can also be applied only on the parent viewgroup of the edittexts.

 

Example:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:focusableInTouchMode="true">

    <android.support.design.widget.TextInputLayout
        android:id="@+id/msg_input"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:layout_toLeftOf="@+id/msg_input_remove_icon"
        android:layout_toStartOf="@+id/msg_input_remove_icon"
        android:hint="@string/message">

        <android.support.design.widget.TextInputEditText
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    </android.support.design.widget.TextInputLayout>

    <ImageView
        android:id="@+id/msg_input_remove_icon"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentEnd="true"
        android:layout_alignParentRight="true"
        android:layout_centerVertical="true"
        android:src="@android:drawable/ic_delete" />
</RelativeLayout>

 

Adding dividers to a RecyclerView and choosing which ones to show (Custom RecyclerView.ItemDecoration)

Most of the tutorials I found online say to override the “getItemOffsets” method and set the outRect.setEmpty(); on the view you don’t want a divider. This doesn’t seem to work, at least when using the “com.android.support:recyclerview-v7:25.3.1”.

To make it work i had to override the onDraw method. See below code for a custom  ItemDecoration class

 

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.support.annotation.ColorRes;
import android.support.v4.content.ContextCompat;
import android.support.v7.widget.RecyclerView;
import android.util.TypedValue;
import android.view.View;

import uk.co.travelrepublic.travelrepublic.util.CompatUtil;

public class DividerItemDecorationWidget extends RecyclerView.ItemDecoration {
    private final Paint mPaint;

    public DividerItemDecorationWidget(Context context, @ColorRes int color, float heightDp) {
        mPaint = new Paint();
        mPaint.setColor(ContextCompat.getColor(context, color));
        final float thickness = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, heightDp, context.getResources().getDisplayMetrics());
        mPaint.setStrokeWidth(thickness);
    }

    @Override
    public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
        // we set the stroke width before, so as to correctly draw the line we have to offset by width / 2
        final int offset = (int) (mPaint.getStrokeWidth() / 2);

        // this will iterate over every visible view except the last one, we don't want a divider in the last view
        for (int i = 0; i < (parent.getChildCount() - 1); i++) {
            final View view = parent.getChildAt(i);
            final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) view.getLayoutParams();

            final int position = params.getViewAdapterPosition();

            if (position < state.getItemCount()) {
                c.drawLine(view.getLeft(), view.getBottom() + offset, view.getRight(), view.getBottom() + offset, mPaint);
            }
        }
    }
}

 

and if you want the divider lines to be drawn on top of the views (this is needed if you have a background color on the views, if this is not used then the divider lines will be hidden behind the background color)

 

@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
    final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) view.getLayoutParams();

    // we want to retrieve the position in the list
    final int position = params.getViewAdapterPosition();

    // and add a separator to any view but the last one
    if (position < state.getItemCount()) {
        outRect.set(0, 0, 0, (int) mPaint.getStrokeWidth()); // left, top, right, bottom
    } else {
        outRect.setEmpty(); // 0, 0, 0, 0
    }
}

 

I got some ideas from David Medenjak blog post