SlideShare a Scribd company logo
Droidcon2013 android experience lahoda
IMPROVING ANDROID EXPERIENCE FOR
BOTH USERS AND DEVELOPERS
droidcon Berlin 2013, Pavel Lahoda,Actiwerks Ltd.
LET’S HAVE A LITTLE WARMUP
ANDROID.UTIL.LOG
HOW MANYTIMESYOU’VETYPEDTHIS ?
prn.log("Index=" + i);
HOW ABOUTTHIS ?
public static String cc(int depth) {
	 	 if(skipCallStackCode == true) {
	 	 	 return NA; // short-circuit for production
	 	 }
	 	 StackTraceElement[] ste = getStackTrace(null);
	 	 int depthCount = 0;
	 	 boolean shallowFlag = true;
	 	 for(StackTraceElement element : ste) {
	 	 	 if(prn.class.getName().equals(element.getClassName()) == true) {
	 	 	 	 // always ignore elements that are above this class in the stack
	 	 	 	 shallowFlag = false;
	 	 	 } else {
	 	 	 	 if(shallowFlag == false) {
	 	 	 	 	 if(depthCount >= depth) {
	 	 	 	 	 	 String name = element.getFileName();
	 	 	 	 	 	 if(name != null) {
	 	 	 	 	 	 	 if(name.endsWith(".java")) {
	 	 	 	 	 	 	 	 name = name.substring(0, name.length()-5);
	 	 	 	 	 	 	 }
	 	 	 	 	 	 } else {
	 	 	 	 	 	 	 name ="[?]";
	 	 	 	 	 	 }
	 	 	 	 	 	 return name;
	 	 	 	 	 } else {
	 	 	 	 	 	 depthCount++;
	 	 	 	 	 }
	 	 	 	 }
	 	 	 }
	 	 }
	 	 return NA_BUG;
	 }
HOW DOES IT WORK ?
GITHUB LINK
WHERE ISTHE UX ?
HAVE TIME TO WORK ON AWESOME
STUFF !
IMPORTANCE OF HAVING
YOUR VIEW FLEXIBLE
ANDROID AND WEB COMMON STUFF
UNLIMITED AMOUNT OF DISPLAY SIZES
WEBTRENDS: RESPONSIVE DESIGN
ANDROIDTRENDS: LOTS OF WORK
CURRENT ANDROID LAYOUTS ARE
NOT FLEXIBLE ENOUGH
ALTERNATIVE:
USE PURE JAVAVIEWGROUP
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int widthSpecSize = View.MeasureSpec.getSize(widthMeasureSpec);
	 tinyGap = widthSpecSize/100;
	 myComponent.measure(View.MeasureSpec.makeMeasureSpec(LayoutParams.WRAP_CONTENT, View.MeasureSpec.EXACTLY),
	 	 	 	 View.MeasureSpec.makeMeasureSpec(LayoutParams.WRAP_CONTENT, View.MeasureSpec.EXACTLY));
// more component’s measuring goes there
	 setMeasuredDimension(widthSpecSize, newHeight);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
myComponent.layout(x, y, x+myComponent.getMeasuredWidth(), y+titleLabel.getMeasuredHeight());
// more component’s layout goes there
}
ONMEASURE() - PLACE FORYOUR LOGIC
NO NEEDTO REBIND COMPONENTS OR
CALL SLOW LAYOUT INFLATE CODE
WORKS GREAT FOR ORIENTATION
CHANGES
BBC NEWS FORTABLETS EXAMPLE
INSPIRATION:
WEB RESPONSIVE LAYOUT
DEAL WITH MANY DIFFERENT SCREEN
SIZES
STANDOUT - FLOATING WINDOWS
ACTION BAR
ONE OF WORST EXAMPLES
OF API DESIGN
ACTIONBAR IS NOT A DESCENDANT OF
AVIEW
BLOG.PERPETUMDESIGN.COM/2011/08/
STRANGE-CASE-OF-DR-ACTION-AND-
MR-BAR.HTML
ACTIONBARSHERLOCK
ACTION BAR PLUS
PROBLEM ?
AB OCCUPIES ~10% OF SCREEN SPACE
FUNCTIONALITY OFTEN REDUCEDTO
BRANDING
FLY-OUT MENU:A FACEBOOK SOLUTION
NOT CONSISTENT WITHTHE REST OF
ACTIONBAR FUNCTIONALITY
ACTIONBAR PARTS
ACTIONBAR BEHAVIOR
Touch here shows
a menu with options
Touch here moves up in hierarchy
Touch here performs action
Touch here show a menu with options
Any extension should stay consistent with this
DON’T CONFUSEYOUR USERS
OWN APPS’D USE SOME UX FACELIFT
STILL WANT MORE FROMTHE
ACTIONBAR AREA ?
ACTION BAR PLUS
CUSTOM ACTIONBAR IMPLEMENTATION
EMBRACE EXTRA DIMENSION
TWOTYPES OF NAVIGATION
MAKE SURETHERE IS DEAD AREATO
SEPARATE FROM NOTIFICATION BAR
GESTURE
USE MIDDLE AS BONUS CONTENT
SUCH AS STUFF OUTSIDETHE APP
2D JUST ON OVERFLOW
ACTIONS ARE EITHERTOUCH
OR SWIPE DOWN
ACCESSTO HELP ON ACTIONS
EMBRACE MULTITOUCH
EASY SPLITVIEW FEATURE
BROADCASTTHE AVAILABLE SCREEN
actiwerks.intent.splitview
DESCRIPTION OFTHE INTENT APPEARS SOON ONTHE OPENINTENTS.ORG
BROADCAST DETAILS
private Intent splitIntent;
splitIntent = new Intent();
splitIntent.setAction("actiwerks.intent.splitview");
splitIntent.removeExtra("APP_SPLIT_SIZE");
splitIntent.putExtra("APP_SPLIT_SIZE", windowVerticalOffset);
getContext().sendBroadcast(splitIntent);
RECEIVETHE BROADCAST
<receiver android:name="AppSplitViewReceiver" >
<intent-filter>
<action android:name="actiwerks.intent.splitview" />
</intent-filter>
</receiver>
public class AppSplitViewReceiver extends BroadcastReceiver {
	 @Override
	 public void onReceive(Context context, Intent intent) {
	 	 if(intent.getAction() != null &&
intent.getAction().equals("actiwerks.intent.splitview")) {
	 	 	 int peekSize = intent.getIntExtra("APP_SPLIT_SIZE", -1);
	 	 	 // Handle the intent in the app, resize the window/layout accordingly
	 	 }
	 }
}
ACTIONBARPLUS INTHE GITHUB
FUN WITHTHE LISTVIEW
PROBLEM ?
ARRAYADAPTER API NOT DESIGNED
FOR GENERICVIEWGROUP
interface ViewAdapterBinder<T, V> {
public void bindViewToData(V view, T data);
}
public class ArrayViewGroupAdapter<T, V extends ViewGroup> extends ArrayAdapter<T>
BIND DATATOVIEW
public View getView(int position, View convertView, ViewGroup parent){
	 	
	 // assign the view we are converting to a local variable
	 V v = null;
	 try {
	 	 v = (V) convertView;
	 } catch(ClassCastException ccex) {}
// safe to ignore, keep null to force new instance to be created
	 // first check to see if the view is null. if so, we have to inflate it.
	 // to inflate it basically means to render, or show, the view.
	 if (v == null) {
	 	 v = getInstanceOfV();
	 }
	 T data = getItem(position);
	 if (data != null && binder != null) {
	 	 binder.bindViewToData(v, data);
	 } else {
	 	 // signal error here
	 	 prn.log("Can't bind data to view " + position);
	 }
	 // the view must be returned to our activity
	 return v;
}
private V getInstanceOfV() {
ParameterizedType superClass = (ParameterizedType)
getClass().getGenericSuperclass();
	 Class<V> type = (Class<V>) superClass.getActualTypeArguments()[1];
try {
return type.getDeclaredConstructor(Context.class).newInstance(getContext());
} catch (Exception ex) {
// Oops, no default constructor
throw new RuntimeException(ex);
}
}
public class SampleArrayAdapter extends ArrayViewGroupAdapter<SampleData, SampleListItem> {
	 public SampleArrayAdapter(Context context) {
	 	 super(context, new ArrayViewGroupAdapter.ViewAdapterBinder<SampleData, SampleListItem>() {
	 	 	
	 	 	 @Override
	 	 	 public void bindViewToData(SampleListItem view, SampleData data) {
	 	 	 	 view.setTitle(data.getTitle());
	 	 	 	 view.setDetails(data.getDetails());
	 	 	 }
	 	 	
	 	 });
	 }
}
ATYPE-SAFE, REFACTORING FRIENDLY
SOLUTION
ADVANTAGES FORTHE DEVELOPER AND
THE USER
INSTANT LISTS WITH INTROSPECTION
OBJECTFORMS.COM
FLEXIBLE LAYOUT ALLOWS RESIZING
PINCHTO ZOOM GESTURE IN LISTS
TIME AND DATE PICKER
PROBLEM ?
UNLIKE OTHER WIDGETS,
TIME & DATE PICKER NEEDS DIALOG
(OR PLENTY OF SPACE)
SOLUTION:
SPLIT EDITING INTO SPECIALIZED
TIME & DATE KEYBOARD
DIRECT MANIPULATION GESTURE
“KEYBOARD” FOR DATE SELECTION
NOTOUCH AT ALL
KINETIC GESTURES
SHAKE GESTURE
- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event
{
if (motion == UIEventSubtypeMotionShake) {
[self showAlert];
}
}
//When a gesture is detected (and ended) the showAlert method is called.
-(IBAction)showAlert
{
UIAlertView *alertView = [[UIAlertView alloc]
initWithTitle:@"ShakeGesture Demo"
message:@"Shake detected"
delegate:nil
cancelButtonTitle:@"OK"
otherButtonTitles:nil];
[alertView show];
}
AREATHAT IS NOT GETTINGTHE LOVE
IT DESERVERS
TIM BRAY : SENSPLORE
SENSOR FUSION
http://
www.youtube.com/
watch?
v=C7JQ7Rpwn2k
SAMSUNG GESTURES
HELP US SHAPETHE FUTURE
http://www.kineticgestures.org
TAKEWAY
Q & A
THANKYOU
PAVEL LAHODA
PAVEL@ACTIWERKS.COM
@PERPETUMDESIGN

More Related Content

Droidcon2013 android experience lahoda