11 November 2015

Android layout with view fixed to bottom


I recently submitted a stack overflow question about a problem I was having. I didn't get the answer I was looking for so eventually I answered it myself.

The concept I wanted to achieve was to have a view stick to the bottom of the screen. Pretty easy in a relative layout with alignParentBottom="true". However the screen was a registration screen, so it had edit text boxes. When you click on an edit text box, the soft keyboard appears. The problem I then had of course was that my bottom view then popped up to the top of the keyboard and obscured most of the screen.



The above diagram goes a little way to representing what I was seeing, with three being the keyboard and two being the view I wanted stuck to the bottom. The overall container being a RelativeLayout with the blue being a ScrollView and the red alignParentBottom="true".

After much head scratching I finally stumbled across a solution, although it was a bit different to what I was expecting.

First I moved the red bottom view into the scrollview and added a stretcher view with a height of zero.

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

    <ScrollView
        android:layout_alignParentTop="true"
        android:layout_alignParentBottom="true"
        android:isScrollContainer="false">

        <LinearLayout
            android:id="@+id/content"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">

            <EditText />
            <EditText />

            <View
                android:id="@+id/stretcher"
                android:layout_width="match_parent"
                android:layout_height="0dp" />

            <TextView
                android:id="@+id/2"
                android:layout_gravity="bottom"
                text="2" />
        </LinearLayout>
    </ScrollView>
</RelativeLayout>


The next step was to add a view tree observer.

    final View mainLayout = getView();
    final View mainContent = getView().findViewById(R.id.content);
    final View stretcherView = getView().findViewById(R.id.stretcher);

    //Main layout uses weight some, so we can't hard code the size of the circles.
    //We must dynamically re-size
    mainLayout.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            if (android.os.Build.VERSION.SDK_INT >= 16) {
                mainLayout.getViewTreeObserver().removeOnGlobalLayoutListener(this);
            } else {
                mainLayout.getViewTreeObserver().removeGlobalOnLayoutListener(this);
            }

            //Calculate the desired height of the stretcher view to be the remainder between full screen and content.
            int stretchHeight = mainLayout.getHeight() - mainContent.getHeight();

            //Apply calculated height remainder to stretched view.
            //This enables our bottom box to be pushed to the bottom without obstructing the content when the keyboard appears.
            LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) stretcherView.getLayoutParams();
            params.height = stretchHeight;
            stretcherView.setLayoutParams(params);
        }
    });


This listener watches the entire screen and then measures the difference between the full screen and the scrollview. It then inflates the stretcher view by this difference. What we're effectively doing is nudging the bottom view to the bottom of the screen. Now when we load the page the bottom view sits nicely on the bottom of the screen, but when the keyboard moves the bottom view stays underneath and appears in the scroll.

Hope this helps somebody else!

27 October 2015

Android custom view, interesting lessons


So here's an interesting one, I recently created a custom view in Android. Basically a specific shape that a client wanted to frame some text. To begin with the custom view was very simple and I used a relative layout to hold the view in place and the centred brand name inside.


The java comprised of a Paint with a fill in the view initializer and in the onDraw method a Path drawn on the canvas with drawPath().

Unfortunately vertical centre was of the whole view, I needed it to be centred by the left side (a). Remember the view is more than what you can see and in this case it includes the invisible part of the rectangle above the slope. My first impulse was to push it down with some marginTop, but this would of course not work consistently on smaller devices.
So what I needed to do was measure a and centre the text accordingly. I grabbed height and width in onMeasure using MeasureSpec.getSize. Then used the following code to I found on stack overflow:

int yPos = (int) ((mHeight / 2) - ((mTextPaint.descent() + mTextPaint.ascent()) / 2));
canvas.drawText("", 20, yPos, mTextPaint);

This allowed me to centre the text as required. I added a paint object with some formatting:

        //Text font
        mTextToShow = getContext().getResources().getString(R.string.some_text);
        Typeface ty = Typeface.createFromAsset(getContext().getAssets(), "fonts/some_font.otf");

        //Text size
        Resources resources = getContext().getResources();
        float scale = resources.getDisplayMetrics().density;

        mTextPaint = new Paint();
        mTextPaint.setAntiAlias(true);
        mTextPaint.setStyle(Paint.Style.FILL);
        mTextPaint.setTextSize((int) (20 * scale));
        mTextPaint.setTypeface(ty);
        mTextPaint.setColor(getResources().getColor(R.color.primary_white));


I now needed to do one more thing, the view was to be a link. I'm a huge fan of using Android's state to change text colour when its clickable. This helps the user know they've clicked something and it looks good too. However I had no idea how to do this, if I'd made an xml layout for this view I could do it, but using drawText meant I had no xml. Hmmm.

A few Google searches and even the mighty stack overflow didn't get me very far. Then I started to think, don't all view's have a onPressed or an onStateChanged method? I hit Ctrl Space and scanned through my options. OnPressed was there but I needed more... drawableStateChanged. Sounds promising. A few minutes later I had a working guess and it was building. Hey preseto! It worked, check this out:
    @Override
    protected void drawableStateChanged() {
        if(isPressed()){
            mTextPaint.setColor(getResources().getColor(R.color.primary));
        }else{
            mTextPaint.setColor(getResources().getColor(R.color.primary_white));
        }
        invalidate();

        super.drawableStateChanged();
    }

Hope this helps, happy coding


28 July 2015

Top Ten Free Android Wear Watch Faces

I've recently got myself an Android Wear Watch. It’s actually an Asus ZenWatch and thus far I’ve really enjoyed it. In using it I'm constantly on the lookout for new and attractive watch faces. There are hundreds of different watch faces out there and developers build more every day. I myself have created a few watch faces and am looking forward to launching a new digital watch face soon. I thought I’d do a list of my favourite free watch faces.

I’ll specify that the following list of free watch faces are almost all digital. Yes I’m one of those people who own a digital watch. I dislike analogue watches and always will.

Orbiting this at a distance of roughly ninety-eight million miles is an utterly insignificant little blue-green planet whose ape-descended life forms are so amazingly primitive that they still think digital watches are a pretty neat idea.
- Douglas Adams (Hitchhiker's Guide To The Galaxy)

Here is a list of the top ten free watch faces I’ve found so far:

  1. Weather Watch face
    https://play.google.com/store/apps/details?id=com.pizzaentertainment.weatherwatchface&hl=en
    This is a really beautiful watch face. Granted it’s “fremium”, you can install it for free and then pay for more features, but the basic model is really great.
  2. LED Clock
    https://play.google.com/store/apps/details?id=com.seenapps.ledclock_face&hl=en
    Very simple, very elegant, I really like this watch face. Just LED numbers, nothing else.
  3. Word Clock
    https://play.google.com/store/apps/details?id=de.amnoid.thakis.wordclock&hl=en
    I love this watch face, whoever thought of this is a genious. I wish I’d come up with the idea. It shows the time as words, which is really fun. No date and no battery info.
  4. Binary
    https://play.google.com/store/apps/details?id=com.halachev.martin.android.wearable.binarywatchface&hl=en
    The ultimate geek watch face. Time displayed in highlighted circles representing 8,4,2,1 for the hour and so on. Really clever. Date in the background can be a bit hard to decipher and day of the week is missing.
  5. Matrix
    https://play.google.com/store/apps/details?id=net.dheera.wearfacematrix&hl=en Probably not great for battery and becomes a little annoying. Still a really fun idea. Doesn’t display any date or battery levels.
  6. Space and Time
    https://play.google.com/store/apps/details?id=net.genggao.spaceandtime&hl=en
    Colourful and fun, these things please me.
  7. Vigor Watch Face
    Comes free with either Google Wear or Asus, either way it’s a lovely little watch face. Ties nicely into the numbers of steps you’ve done in a day.Lacks the month and year, but I should really know that shouldn’t I?
  8. QWF
    https://play.google.com/store/apps/details?id=qwf.ammarptn.com.qwf&hl=en
    This is a really lovely little watch face. Super simple, super pretty. It lacks a day of the week and some of the information the others have, but that’s excusable.
  9. Un Petit Monde
    https://play.google.com/store/apps/details?id=net.unpetitmonde.miniadventure.watchface
    No options, battery and limited date display, but a fun design with a relaxing background effect.
  10. Simple Watch Face
    https://play.google.com/store/apps/details?id=com.koherent.simplisticwatchface&hl=en
    Does exactly what it says on the tin. A nice simple watch face with good colours and a good idea for a theme. No 24 hour, no date, no battery.




09 July 2015

Android Wear - A week with a smartwatch

Thus far, I've not been impressed with smartwatches, I like new toys but even Android Wear has yet to impress me. The watches are just too big, I don’t buy into the charging every day thing and frankly I'm just not excited about the benefits. I've had a Casio watch which I've worn every day for about fifteen years and I've never charged it. Not once!

Roughly a week ago my work bought an Asus Zenwatch running Android Wear for testing and developing on. Not one to look a gift horse in the mouth and always up for some new programming and tinkering I was quite looking forward to having a play. I've previously written a test app but I used an emulator for this: http://webdeveloperpadawan.blogspot.co.uk/2014/07/android-wearables-first-go.html

My first impression of the Zen Watch was actually very good. It’s not nearly as fat as the LG Moto 360 which a few of my colleagues have and both the leather strap and the face have a nice look and feel. It is square but I can’t imagine that would bear any consequence to anyone.

It is too big, my tiny girl wrists are very twig like and the watch doesn't fit well and looks huge. There are huge gaps in the corners where the watch overlaps the flat bit of my wrist. That said it is comfortable and easy to get used to.

Turn on and set-up are a breeze and you can play with the watch faces on the play store which is fun for a few minutes.

Then it hits you….what now? You can’t really do anything with it! This is what is quite funny, people spot it on your wrist quite quickly and you honestly can’t show them much. It’s a passive device, you can’t play games on it, you can’t type on it, it just responds.

Sure you can use OK Google which is impressive, but I don’t talk to my phone and I’m unlikely to talk to this. It does work well and you can send messages and such by talking. Word to the wise, don’t try this after half a bottle of wine as I ended up sending all sorts of random messages to various people.

The beauty of the watch, and where I'm finally coming to actually really like it, is when you need to react to something. For example when one of the millions of spam messages comes to my phone, I don’t actually need to get my phone out to check it. I can immediately check and prioritise what’s important. The other thing that really stands out is the vibrate on your wrist, this is great as I often miss a call or message on my phone. The wrist vibrate is subtle but also unmissable. The ability to not get your phone out of your pocket sounds unbelievably lazy, but the watch works. For example in meetings or when you’re busy doing something, you can prioritise at a glance. Is this just another meaningless message from some inane whatsapp group or is it a message from Nest saying my house is on fire?

The battery is much less of a big deal than I thought, I'm getting two or three days of use out of it (I turn it off at night) and can just chuck it on its gradle for a bit while I'm working on it. Will it get tired….possibly, but so far its really not bothered me.

The Oatmeal have a fantastic post about the watch, all be it the apple one…. and it’s got funnier pictures than I do:

So to summarize, I'm impressed, very impressed. It can be surprisingly useful and does make life much easier. Million dollar question, would I buy one? No. They’re too big, when technology advances and the size comes way down, yes I will.

16 June 2015

Android integration with Chrome Custom Tabs


Announced at Google IO 2015 was the ability to integrate custom tabs in Android. Much like Facebook has been using it’s own browser like tab to open links, this ability is now available in Android with Chrome. This is great news as it allows developers to integrate a web link and maintain some of the look and feel of their app. You can add toolbar colors, animations and even a button.


Before going any further as of June 2015 you need to install Chrome from the dev channel:
Version 45 has this feature, they say it’ll take about twelve weeks to roll through to release.

This works in any version of Android, so don’t worry about M or any of that. It degrades really nicely, so if your client has the feature in Chrome, it’ll slide in and out beautifully. If not, then it’ll open like a regular intent. Although your custom in animation will probably show.

First you need to create four standard in and out animations, left in, left out, right in, right out.
Then you need to define some final constants which will be used in the intent extras:
private static final String EXTRA_CUSTOM_TABS_SESSION_ID = "android.support.CUSTOM_TABS:session_id";
public static final String EXTRA_CUSTOM_TABS_EXIT_ANIMATION_BUNDLE = "android.support.CUSTOM_TABS:exit_animation_bundle";
private static final String EXTRA_CUSTOM_TABS_TOOLBAR_COLOR = "android.support.CUSTOM_TABS:toolbar_color";

Then you can launch like this from your activity:

String url = "http://www.google.com/";
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
intent.putExtra(EXTRA_CUSTOM_TABS_SESSION_ID, -1);
intent.putExtra(EXTRA_CUSTOM_TABS_TOOLBAR_COLOR, getResources().getColor(R.color.colorPrimary));

if(android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
    Bundle finishBundle = ActivityOptions.makeCustomAnimation(MainActivity.this, R.anim.slide_in_left, R.anim.slide_out_right).toBundle();
    intent.putExtra(EXTRA_CUSTOM_TABS_EXIT_ANIMATION_BUNDLE, finishBundle);
    Bundle startBundle = ActivityOptions.makeCustomAnimation(MainActivity.this, R.anim.slide_in_right, R.anim.slide_out_left).toBundle();
    startActivity(intent, startBundle);
}else{
    startActivity(intent);
}


Note that basically all we are doing is launch an intent.ACTION_VIEW but we’re tweaking it with extras so Chrome can interpret this request, slightly differently.
That’s it!

31 May 2015

Android Design Support Library Collapsing Toolbar


Following Google IO I'm always that much more inspired to try a few new things with Android.
Shortly after IO I noticed this new post on the devlopers blog:
http://android-developers.blogspot.co.uk/2015/05/android-design-support-library.html

I immediately loved the CollapsingToolbarLayout as I've had to make something similar myself and never quite got it perfect. The fact that Google are releasing quick and easy ways to implement these design elements is absolutely fantastic. Long may it continue!

When I saw Ian Lake's post on this collapsing toolbar I was super keen to give them a go:
https://plus.google.com/+IanLake/posts/QGR5XNcPPeG

I didn't get especially far until this example from Chris Banes:
https://github.com/chrisbanes/cheesesquare

I decided (as usual) to make mine as simple as possible, stripping out as much of the superfluous stuff as I could.

First we need the support and design libraries:
    compile 'com.android.support:appcompat-v7:22.2.0'
    compile 'com.android.support:design:22.2.0'
    compile 'com.android.support:recyclerview-v7:22.2.0'

First thing we'll do is the xml for our main activity
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    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/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="?attr/colorPrimary"
            app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
            app:layout_scrollFlags="scroll|enterAlways" />

        <TextView
            android:text="@string/hello_world"
            android:padding="20dp"
            android:layout_width="match_parent"
            android:textColor="#00FF00"
            android:layout_height="wrap_content"/>
    </android.support.design.widget.AppBarLayout>

    <android.support.v7.widget.RecyclerView
        android:id="@+id/activity_main_listview"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior"/>
</android.support.design.widget.CoordinatorLayout>

The important bit here is the AppBarLayout which contains the Toolbar and a TextView which I want to hover over the top of the listview.

Second you'll notice we're using a RecyclerView which is new to me but looks to be more powerful than Listview.

Our ActivityMain just passes an ArrayList of Strings too the Recycler View
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.activity_main_listview);
recyclerView.setLayoutManager(new LinearLayoutManager(recyclerView.getContext()));
recyclerView.setAdapter(new MyRecyclerView(this, players));

Oh and of course don't forget to make sure your Activity uses AppCompatActivity and your manifest has a theme which overrides or implements Theme.AppCompat.Light.NoActionBar
You'll need the MyRecylcerView class but that's fairly boring and I borrowed most of it from Chris Banes, so I'll let you look at that in the git repo (bottom).

Now we need to look at the detail page where we use CollapsingToolbarLayout. First the xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/main_content"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true">

    <android.support.design.widget.AppBarLayout
        android:id="@+id/appbar"
        android:layout_width="match_parent"
        android:layout_height="400dp"
        android:theme="@style/ActionBarPopupThemeOverlay"
        android:fitsSystemWindows="true">

        <android.support.design.widget.CollapsingToolbarLayout
            android:id="@+id/collapsing_toolbar"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:layout_scrollFlags="scroll|exitUntilCollapsed"
            android:fitsSystemWindows="true"
            app:contentScrim="@color/colorPrimary"
            app:expandedTitleMarginStart="48dp"
            app:expandedTitleMarginEnd="64dp">

            <ImageView
                android:id="@+id/backdrop"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:scaleType="centerCrop"
                android:fitsSystemWindows="true"
                app:layout_collapseMode="parallax" />

            <android.support.v7.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                android:theme="@style/ActionBarPopupThemeOverlay"
                app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
                app:layout_collapseMode="pin" />
        </android.support.design.widget.CollapsingToolbarLayout>
    </android.support.design.widget.AppBarLayout>

    <android.support.v4.widget.NestedScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical"
            android:paddingTop="24dp">

            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:padding="20dp"
                android:text="All your base are belong to me." />

            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:padding="20dp"
                android:text="All your base are belong to me." />

            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:padding="20dp"
                android:text="All your base are belong to me." />

            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:padding="20dp"
                android:text="All your base are belong to me." />

            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:padding="20dp"
                android:text="All your base are belong to me." />

            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:padding="20dp"
                android:text="All your base are belong to me." />

            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:padding="20dp"
                android:text="All your base are belong to me." />

            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:padding="20dp"
                android:text="All your base are belong to me." />

            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:padding="20dp"
                android:textColor="@color/colorAccent"
                android:text="All your base are belong to me." />
        </LinearLayout>
    </android.support.v4.widget.NestedScrollView>
</android.support.design.widget.CoordinatorLayout>

Here we use a NestedScrollView instead of a RecyclerView, hence the big list of TextViews

The Activity is even simpler here, we read in the extra and setup the toolbar title and background image, then setup the action bar so it's an up navaigation and set the title:
final Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);

CollapsingToolbarLayout collapsingToolbar = (CollapsingToolbarLayout) findViewById(R.id.collapsing_toolbar);
collapsingToolbar.setTitle(muppetName);

That's basically it, a few new concepts and tools here but its super easy.

Here's the GitHub repo of all of this:
https://github.com/jimbo1299/androiddesigntest


12 May 2015

Android Auto First Play

Sadly I'm not lucky enough to have an Android Auto headset in my car, nor will my current car support one. However, I am desperately keen to have Android Auto in my car, to me it make so much sense as most proprietary systems really are awful. So in lieu of an actual system to play with, I thought I’d give Android Auto app creation a go, and see how it worked.

First of all read the dev guide:

There are currently limitations, meaning only Audio and Messaging apps are available, so I thought I’d have a crack at creating an Audio app. I’m really not looking at a shiny well designed app here, I just want to get a proof of concept type app out the door.

  1. Setup
    1. Create a new project selecting Android 5.0 (Api 21) or newer as the target
    2. Import support library (22.1.1 or better) in gradle
compile 'com.android.support:appcompat-v7:22.1.1'
    1. Open SDK manager and install “Android Auto API Simulators” from the Extras branch

  1. Update Android Project to use Auto
We need to tell Android Studio we’re creating an Auto project, so create an xml folder in the res directory and add a file named
automotive_app_desc.xml
With the following contents

<automotiveApp>
    <uses name="media" />
</automotiveApp>

Now tell the manifest where to find this file by adding inside the application tag:

<meta-data android:name="com.google.android.gms.car.application" android:resource="@xml/automotive_app_desc"/>

You can also give yourself an icon for your app

<meta-data android:name="com.google.android.gms.car.notification.SmallIcon" android:resource="@mipmap/ic_launcher" />

  1. Install the simulator
This is explained here:
You basically need to use adb to install an app which is supplied in the auto simulator downloaded in step 2. You can find the apk here:
<sdk>/extras/google/simulators/media-browser-simulator.apk
This isn’t what I expected at all. I was expecting a virtual device, but instead you get a simulator that runs on your actual phone or device and simulates the two types of android auto app. It’s a bit odd, but I guess it works.
If you’re setup you should find an app on your phone named “Media Sim”, run this and you should see the Google Play App running and working fine.

Code!

OK Now we’re ready to write some code. Don’t forget, I’m just creating a proof of concept Audio app here. So instead of streaming music I’ve copied an mp3 to res/raw and I’m going to try and play this file.

Create a service in the Manifest:

<service android:name=".MusicService" android:exported="true">
    <intent-filter>
        <action android:name="android.media.browse.MediaBrowserService"/>
    </intent-filter>
</service>

Create a class in your package and make it extend MediaBrowserService. This will mean you’ve got to implement the method onLoadChildren() and onGetRoot(). Now as you will see if you walk through the Google example this is how we create a tree structure of bands, albums and songs. Meaning you can traverse your music library. I was simply looking for the quickest route through all this to display one file, so I’ve created an array list of one mediaItem which is loaded with my mp3 and returned.
If you’re struggling to figure what to do here I advise to download the Google sample:

I’ve also created a MediaSessionCallback class which extends MediaSession.Callback. As you can see by the implemented methods, this is just a callback class for the play, pause, skip etc buttons. My version is pretty quick and dirty. Google provides a standard button interface for audio apps and in order to interface with these buttons we’re going to use the MediaSession callback.

Here’s the manifest:


<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.wunelli.android.autotest" >

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >

        <meta-data android:name="com.google.android.gms.car.application"
                   android:resource="@xml/automotive_app_desc"/>

        <meta-data android:name="com.google.android.gms.car.notification.SmallIcon"
                   android:resource="@mipmap/ic_launcher" />

        <activity
            android:name=".ActivityMain"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <service android:name=".MusicService" android:exported="true">
            <intent-filter>
                <action android:name="android.media.browse.MediaBrowserService"/>
            </intent-filter>
        </service>
    </application>
</manifest>



Here’s the code for the service:

package com.wunelli.android.autotest;

import android.media.MediaMetadata;
import android.media.MediaPlayer;
import android.media.browse.MediaBrowser;
import android.media.session.MediaSession;
import android.os.Bundle;
import android.service.media.MediaBrowserService;
import android.util.Log;

import java.util.ArrayList;
import java.util.List;

public class MusicService extends MediaBrowserService{

    private MediaSession mSession;
    MediaPlayer mPlayer;

    private static final String TAG = MusicService.class.getSimpleName();
    public static final String CUSTOM_METADATA_TRACK_SOURCE = "__SOURCE__";

    @Override
    public void onCreate() {
        super.onCreate();
        Log.d(TAG, "onCreate");

        initMedia();

        // Start a new MediaSession
        mSession = new MediaSession(this, "MusicService");
        setSessionToken(mSession.getSessionToken());
        mSession.setCallback(new MediaSessionCallback());
        mSession.setFlags(MediaSession.FLAG_HANDLES_MEDIA_BUTTONS | MediaSession.FLAG_HANDLES_TRANSPORT_CONTROLS);
    }

    @Override
    public BrowserRoot onGetRoot(String clientPackageName, int clientUid, Bundle rootHints) {
        Log.d(TAG, "OnGetRoot: clientPackageName=" + clientPackageName + "; clientUid=" + clientUid + " ; rootHints=" + rootHints);

        return new BrowserRoot("__ROOT__", null);
    }

    private void initMedia(){
        mPlayer = MediaPlayer.create(this, R.raw.roboto);
    }

    @Override
    public void onLoadChildren(String parentId, Result<List<MediaBrowser.MediaItem>> result) {

        List<MediaBrowser.MediaItem> mediaItems = new ArrayList<>();

        MediaMetadata item = new MediaMetadata.Builder()
                .putString(MediaMetadata.METADATA_KEY_MEDIA_ID, "1")
                .putString(CUSTOM_METADATA_TRACK_SOURCE, "roboto.mp3")
                .putString(MediaMetadata.METADATA_KEY_ALBUM, "Kilroy Was Here")
                .putString(MediaMetadata.METADATA_KEY_ARTIST, "Styx")
                .putLong(MediaMetadata.METADATA_KEY_DURATION, 330000)
                .putString(MediaMetadata.METADATA_KEY_GENRE, "rock")
                .putString(MediaMetadata.METADATA_KEY_ALBUM_ART_URI, "album_art.jpg")
                .putString(MediaMetadata.METADATA_KEY_TITLE, "Roboto")
                .putLong(MediaMetadata.METADATA_KEY_TRACK_NUMBER, 1)
                .putLong(MediaMetadata.METADATA_KEY_NUM_TRACKS, 1)
                .build();
        String musicId = item.getString(MediaMetadata.METADATA_KEY_MEDIA_ID);

        String hierarchyAwareMediaID = "rock|" + musicId;
        MediaMetadata trackCopy = new MediaMetadata.Builder(item)
                .putString(MediaMetadata.METADATA_KEY_MEDIA_ID, hierarchyAwareMediaID)
                .build();
        MediaBrowser.MediaItem bItem = new MediaBrowser.MediaItem(trackCopy.getDescription(), MediaBrowser.MediaItem.FLAG_PLAYABLE);
        mediaItems.add(bItem);

        result.sendResult(mediaItems);
    }

    private final class MediaSessionCallback extends MediaSession.Callback {
        @Override
        public void onPlay() {
            Log.d(TAG, "play");
            mPlayer.start();
        }

        @Override
        public void onSkipToQueueItem(long queueId) {
            Log.d(TAG, "OnSkipToQueueItem:" + queueId);
        }

        @Override
        public void onSeekTo(long position) {
            Log.d(TAG, "onSeekTo:" + position);
        }

        @Override
        public void onPlayFromMediaId(String mediaId, Bundle extras) {
            Log.d(TAG, "playFromMediaId mediaId:" + mediaId + "  extras=" + extras);
            mPlayer.start();
        }

        @Override
        public void onPause() {
            Log.d(TAG, "pause.");
            mPlayer.start();
        }

        @Override
        public void onStop() {
            Log.d(TAG, "stop.");
            mPlayer.reset();
            initMedia();
        }

        @Override
        public void onSkipToNext() {
            Log.d(TAG, "skipToNext");
        }

        @Override
        public void onSkipToPrevious() {
            Log.d(TAG, "skipToPrevious");
        }

        @Override
        public void onCustomAction(String action, Bundle extras) {
            Log.i(TAG, "Unsupported action: " + action);
        }

        @Override
        public void onPlayFromSearch(String query, Bundle extras) {
            Log.d(TAG, "playFromSearch  query=" + query);
        }
    }
}















01 March 2015

Security isn't a dirty word Blackadder

Hopefully we all understand the concepts behind asymmetric (Public / Private key) encryption. It’s something we use all the time (https, SSL etc) but I've never actually put code to screen and tried to implement it. I've always relied on standard symmetric-key algorithm. So I thought I’d give it a go in Java / Android and along the way I learned a lot. In this blog article I thought I’d outline a few things I've learned. I’ll put some code up as I go, but I’d like to try and focus a bit more on the lessons.
All security is equal, except some more equal than others
We all know in symmetric encryption DES is bad, right?
DES is now considered to be insecure for many applications
http://en.wikipedia.org/wiki/Data_Encryption_Standard#Brute_force_attack


Well in theory public / private key encryption is infinitely better as long as you never give out your private key. Easy peasy, so we choose one of these and away we go:
  • RSA
  • EIGamal
  • Diffie-Helman
So I want to take a basic string “All your base are belong to me” and I want to encrypt it using a public key and decrypt it using a private key.
Rush to code

Impatient as I am I rush to get some code in and find this code to try out:
byte[] data = readBytesFromfile(“mypublickey”);
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(data); 
KeyFactory kf = KeyFactory.getInstance("RSA");
pubKey = kf.generatePublic(keySpec);

Great, now I need a public and private key to test my amazing new code.

I learn a few bits about encryption

I’d heard of PGP and apparently this has no known weaknesses, perfect, I want this! So away I go and find a tool to generate my PGP public and private key. I throw these into my java code and straight away get an error. Hmmm. Something doesn't feel right here. Plus I'm not too sure about PGP and OpenPGP. OK back to wikipedia. Apparently PGP is a protocol, not an algorithm and for its asymmetric files it uses RSA anyway! Doh! So I resort to RSA and now I need to generate an RSA key.


So I've already got puttyGen installed and it I don’t know why it says SSH but it definitely says RSA right there with a big button saying “Generate”. Boom, surely this will work, nothing can stop me now!
Now I get a java error InvalidKeySpecException
Hmm, after some serious time googling I ask stack overflow
http://stackoverflow.com/questions/28218636/invalidkeyspecexception-using-public-key
Although it doesn't solve my problem, Maarten alerts me to the fact that in java I need to use the X509 format.
Hang on SSH is a protocol isn't it? (Back to wikipedia). Right ok so PGP and SSH are protocols that implement asymmetric encryption using the RSA algorithm. I don’t want a protocol, I want to just generate an encrypted string.


To do that I need a public key which java can read. So all I need is to generate a key in the right format….That makes sense.

Using KeyTool and OpenSSL to generate a 509 certificate


This doesn't take me long using java keytool and openssl to generate an x509 certificate.
keytool -genkey -keyalg RSA -keysize 1024 -keystore C:\temp\hello.keystore

keytool -importkeystore -srckeystore C:/temp/hello.keystore -destkeystore C:/temp/hello.p12 -deststoretype PKCS12

openssl pkcs12 -in C:/temp/hello.p12 -out C:/temp/hellonew.pem -nodes

openssl x509 -in C:/temp/hellonew.pem -inform PEM -out C:/temp/hellodernew.der -outform DER

Reading an X509 certificate
Now we need to adapt our code to read the key in the new format.
public static PublicKey getPublicKey(byte[] keyBytes){
    PublicKey publicKey = null;

    if(keyBytes != null) {

        X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);
        KeyFactory kf = null;
        try {
            kf = KeyFactory.getInstance("RSA");
            publicKey = kf.generatePublic(spec);
        } catch (NoSuchAlgorithmException e) {
            Log.e(TAG, "NoSuchAlgorithmException");
            e.printStackTrace();
        } catch (InvalidKeySpecException e) {
            Log.e(TAG, "InvalidKeySpecException " + e.getMessage());
            e.printStackTrace();
        }
    }

    return publicKey;
}

This means we can now use our PublicKey to encrypt our message! Wohoo


Decryption

To decrypt we use a similar function

    public static PrivateKey getPrivateKey(byte[] keyBytes){
        PrivateKey privatekey = null;

         if(keyBytes != null) {
            PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);
            KeyFactory kf = null;
            try {
                kf = KeyFactory.getInstance("RSA");
                privatekey = kf.generatePrivate(spec);
            } catch (NoSuchAlgorithmException e) {
                Log.e(TAG, "NoSuchAlgorithmException");
                e.printStackTrace();
            } catch (InvalidKeySpecException e) {
                Log.e(TAG, "InvalidKeySpecException");
                e.printStackTrace();
            }
        }

         return privatekey;
    }


Encrypting a large file

For various reasons I've also learned you can’t just encrypt a file with your public key. This guy gives an excellent description of what you should be doing:


The basic idea is as such:
  1. Create a session key using symmetric encryption, AES for example.
  2. Then encrypt the file using this session key
  3. Using your public key encrypt the session key
  4. Send the AES encrypted file and the public key encrypted session key together
  5. Your server / recipient uses the private key they have and decrypts the session key then using that decrypts the file.


This method allows for fast encryption and secure transmission. If anyone brute forces the session key, they've only ever got one file. They need to start again for every single new file!

Anyway, that’s about what I've learned on this particular journey. I hope its of some help.