Thursday, December 25, 2014

Android's alternative IPC approche

I hate Android's Services

To be more precise - I hate asynchronous nature of bindService method. Sometimes it is much more convenient to have synchronous way to get AIDL object.

Did you know that almost each Android's *Manager has its own *ManagerService object?
For example ActivityManager and ActivityManagerService or WindowManager and WindowManagerService, etc.

I was always curious about them. You can get each Manager through Context.getSystemService method and it works synchronously. It would be a waste of time and memory to bind all of them at application startup so they must be bound during getSystemService call. After some digging I found out that they are and it's done through hidden "global context object" which is Binder.


How is Binder connected to AIDL?

Generated AIDL Stub extends Binder and overrides onTransact method, while AIDL Proxy wraps Binder and calls its transact method. Actually Binder is just a "gateway" that passes bytes in one direction, so all function calls are serialized into a byte array, passed through a Binder and than deserialized.

So the problem is only to pass Binder and Parcel can do it. If Parcel can - Bundle can do it either. And here it struck me - Binder can be passed through Intents and ContentProviders.


Fun with Intents

You can also have some fun with Intents. I don't know why someone would start Activity and pass AIDL through Intent but it is possible to pass AIDL object to IntentService and track that task's progress.

But Intents are of no interest to me now.


Fun with ContentProviders (CP)

For a long time I hated CPs and their DB-related interface until I found interesting function - ContentProvider.exec. It has simple interface and can receive/return Bundles. And with bundles you can pass complex objects, for example AIDL objects. And it turns out that CPs are synchronous.

Eureka!!! Here is a way to synchronously "bind" to another process. You can just create AIDL stub and return it through CP.

For example this is my AIDL interface:
interface ICentral {
    int getRequestsCount();
    void sendRandomRequest(long userTime, String inputArg, ICallback callback);
}

And my ContentProvider:
public class CentralProvider extends ContentProvider {

    // ...

    @Override
    public Bundle call(String method, String arg, Bundle extras) {
        if (extras != null) {
            extras.setClassLoader(ParcelableBinder.class.getClassLoader());
        }
        switch (Central.Method.valueOf(method)) {
            case GetServiceBinder:
                Bundle bundle = new Bundle();
                bundle.putParcelable("binder", new ParcelableBinder((IBinder) CentralBinder.self));
                return bundle;
        }
        return super.call(method, arg, extras);
    }
}

Now to "client" side. To simplify things I need a wrapper:
public class Central {

    public static final Uri AUTHORITY = Uri.parse("content://dev.matrix.central/");

    private static ICentral sCentral;

    public static ICentral getProxy() {
        if (sCentral == null || !sCentral.asBinder().pingBinder()) {
            Bundle bundle = BaseApp.self().getContentResolver().call(AUTHORITY, Method.GetServiceBinder.name(), null, null);
            bundle.setClassLoader(ParcelableBinder.class.getClassLoader());
            sCentral = ICentral.Stub.asInterface(ParcelableBinder.getBinder(bundle, "binder"));
        }
        return sCentral;
    }
}

And here is how to use it:
int count = 0;
try {
    count = Central.getProxy().getRequestsCount();
} catch (Exception ex) {
    // ...
}

Good:
  • full AIDL support
  • fully synchronous "binding" to remote process
  • seamless handing and reconnected of dead Binders

Bad:
  • you don't have service "connection" so remote process can be killed at any time unless at least one service is running

Performance (tested on Nexus 5 with Android 5.0):
  • AIDL method invokes - 0.2-0.5 ms
  • Binder pinging to check if it is alive - 0.1-0.3 ms
  • hot "bind" (if remote app is running) - 1-2 ms
  • cold "bind" (if remote app is down) - 50-100 ms

Wednesday, December 17, 2014

My "second" first presentation at GlobalLogic's Mobile TechTalk

Not so long ago I had my "second" first presentation at GlobalLogic's Mobile TechTalk.

Why "second" you ask? Because I was supposed to talk during first TechTalk but, unfortunately, I had to go abroad. I like to play with OpenGL from time to time so my topic was about OpenGL, to be more specific about direct access to OpenGL texture's buffer in Android. I have to thank my co-worker Alex for presenting it, so my work was not forgotten :)

Here is post about GlobalLogic's Moble TechTalk #1:
http://globallogic.com.ua/uk/press-releases/mobile-techtalk-lviv/

And now about my real first presentation. I'm a big fan of Android, its UI framework and have spent countless hours investigating how does it work, looking through the sources and so on. I have a lot to talk about but for this presentation I've choosen "overdraw" problem. I had problems with that nasty beast before so, maybe, just maybe, it was interesting to someone. Final presentation was prepared with Alex's help.

And here are links for this presentation on GlobalLogic's Mobile TechTalk #2:
http://globallogic.com.ua/uk/press-releases/welcome-to-lviv-mobile-techtalk-2/
http://globallogic.com.ua/uk/press-releases/lviv-mobile-2014-coverage/

And now my thoughts on all of that - it was awesome!!! Hope others think so as well =)

Sunday, October 26, 2014

Invoking callbacks for multiple subscribers

How often do you need to invoke callbacks for a multiple subscribers? For example when you have few observer-like classes.

Consider foolowing code:

public void foo() {
  // do something
  for (Callback callback : mCallbacks) {
    callback.bar();
  }
  // do something
}

Personally, I hate to write code like this - too many lines of code that is mostly duplicate from other places. Even worst when you need to ensure UI thread execution and few more lines go to Handler...

So what is the solution? Most universal (and probably most elegant as well) solution that I've came up with is to use Reflections or to use Proxy to be more specific. Most people I ask didn't even know about existance of this class. In short it allows us to create a class in runtime which implements any number of interfaces. Yes, this adds some overhead but, frankly, this is quite small overhead if used somewhat sparingly and almost non-existantant when we add Handler.

So here is my callbacks invoker implementation:

public class Invoker<T> {

  public final T object;
  public final List callbacks = new ArrayList<>();

  private Invoker(T object) {
    this.object = object;
  }

  @SuppressWarnings("unchecked")
  public static <T> Invoker create(Class cls) {
    DirectInvocation<T> handler = new DirectInvocation<T>();
    Object object = Proxy.newProxyInstance(
        cls.getClassLoader(), new Class[] { cls }, handler
    );
    return handler.invoker = new Invoker<T>((T) object);
  }

  static class DirectInvocation<T> implements InvocationHandler {
    public Invoker<T> invoker;

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
      for (Object object : invoker.callbacks.toArray()) {
        method.invoke(object, args);
      }
      return null;
    }
  }
}

And now some example how to use it:

...
Invoker<Callback> mInvoker = Invoker.create(Callback.class);
...
mInvoker.callbacks.add(...);
mInvoker.callbacks.add(...);
mInvoker.callbacks.add(...);
...

public void foo() {
  // do something
  mInvoker.object.bar(); // invokes all callbacks
  // do something
}

Now it looks much cleaner, In addition we can easily add Handlers, Threads or anything else to invoke out callbacks inside invoker itelf.

Saturday, October 18, 2014

EditText for CreditCards

Internet has tons of different implementations to add credit card support in Edit.
Most of them listen for text changes and add spaces and I don't like this approche. Mostly because user can see those space while selecting text.

So I will add mine implementation :)

Here is screenshot from Gennymotion:

And sources as well (link on GitHub):

public class CreditCardTransformation implements TransformationMethod {

  private static final Divider sDivider = new Divider();

  @Override
  public CharSequence getTransformation(final CharSequence source, View view) {
    return new SpannedWrapper(source) {
      @Override
      @SuppressWarnings("unchecked")
      public  T[] getSpans(int start, int end, Class type) {
        T[] array = super.getSpans(start, end, type);
        if (!type.isAssignableFrom(Divider.class)) {
          return array;
        }
        Object[] result = (Object[]) Array.newInstance(type, array.length + 1);
        result[0] = sDivider;
        System.arraycopy(array, 0, result, 1, array.length);
        return (T[]) result;
      }

      @Override
      public int getSpanStart(Object tag) {
        if (tag instanceof Divider) {
          return 0;
        }
        return super.getSpanStart(tag);
      }

      @Override
      public int getSpanEnd(Object tag) {
        if (tag instanceof Divider) {
          return length();
        }
        return super.getSpanEnd(tag);
      }
    };
  }

  @Override
  public void onFocusChanged(View view, CharSequence sourceText, boolean focused, int direction, Rect previouslyFocusedRect) {
  }

  static class SpannedWrapper implements Spanned {
    private Spanned mSpanned;
    private CharSequence mSource;

    SpannedWrapper(CharSequence source) {
      mSource = source;
      if (mSource instanceof Spanned) {
        mSpanned = (Spanned) source;
      }
    }

    @Override
    @SuppressWarnings("unchecked")
    public  T[] getSpans(int start, int end, Class type) {
      if (mSpanned != null) {
        return mSpanned.getSpans(start, end, type);
      }
      return (T[]) Array.newInstance(type, 0);
    }

    @Override
    public int getSpanStart(Object tag) {
      if (mSpanned != null) {
        return mSpanned.getSpanStart(tag);
      }
      return 0;
    }

    @Override
    public int getSpanEnd(Object tag) {
      if (mSpanned != null) {
        return mSpanned.getSpanEnd(tag);
      }
      return 0;
    }

    @Override
    public int getSpanFlags(Object tag) {
      if (mSpanned != null) {
        return mSpanned.getSpanFlags(tag);
      }
      return 0;
    }

    @Override
    public int nextSpanTransition(int start, int limit, Class type) {
      if (mSpanned != null) {
        return mSpanned.nextSpanTransition(start, limit, type);
      }
      return 0;
    }

    @Override
    public int length() {
      return mSource.length();
    }

    @Override
    public char charAt(int index) {
      return mSource.charAt(index);
    }

    @Override
    public CharSequence subSequence(int start, int end) {
      return mSource.subSequence(start, end);
    }

    @Override
    public String toString() {
      return mSource.toString();
    }
  }

  static class Divider extends ReplacementSpan {
    @Override
    public int getSize(Paint paint, CharSequence text, int start, int end, Paint.FontMetricsInt fm) {
      int groups = Math.min(3, (end - start) / 4);
      return (int) (paint.measureText(text, start, end) + paint.getTextSize() * groups);
    }

    @Override
    public void draw(Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, Paint paint) {
      int offset = 0;
      int groupStart = start;
      while (groupStart < end) {
        int groupEnd = Math.min(groupStart + 4, end);
        canvas.drawText(text, groupStart, groupEnd, x + offset, y, paint);
        offset += paint.measureText(text, groupStart, groupEnd) + paint.getTextSize();
        groupStart = groupEnd;
      }
    }
  }
}

Tuesday, May 6, 2014

Not editable prefix in EditText

Today I have decided to start sharing my "simple and brilliant" ideas with the world. I don't know if I will continue to do such things in the future but, at least, it worth to try.

So what to start with...

Probably with the latest task I have tried to solve on Android. The task was simple enough - show not editable phone prefix in EditText. Something like this:



Most of the time I try to optimize my code so it implies some limitations:

  1. it must work fast. Actually, it will be a bigger challange for me to make such a simple control work slowly :)
  2. minimize view hierarchy - no need to use "Linear -> Text -> Edit" here
  3. code must look good without any dirty hacks
  4. generalization is good most of the times but no need to be a fanatic
So lets start. Idea is to extend EditText and to override four methods:
  1. onMeasure - to calculate prefix size
  2. onLayout - to position prefix correctly
  3. onDraw - to actually draw prefix
  4. getCompoundPaddingLeft - to offset EditText's content
Here is full class code:

public class PhoneNumberEdit extends EditText {

  private String mPrefix = "+3"; // can be hardcoded for demo purposes
  private Rect mPrefixRect = new Rect(); // actual prefix size

  public PhoneNumberEdit(Context context, AttributeSet attrs) {
    super(context, attrs);
  }

  @Override
  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    getPaint().getTextBounds(mPrefix, 0, mPrefix.length(), mPrefixRect);
    mPrefixRect.right += getPaint().measureText(" "); // add some offset

    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
  }

  @Override
  protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    canvas.drawText(mPrefix, super.getCompoundPaddingLeft(), getBaseline(), getPaint());
  }

  @Override
  public int getCompoundPaddingLeft() {
    return super.getCompoundPaddingLeft() + mPrefixRect.width();
  }
}