Focus

Do you hate when you friends swipe left-right when you show them a photo? You need Focus.

The free version of Focus is a photo gallery add-on that allows you to select one or more items from your favorite gallery application and limit your friends to just viewing those photos.

Your friend can now swipe left or right and will see only the pictures that you have selected. They can pinch zoom and pan photos directly from inside Focus.

If your friend taps on the Back button, they are presented with a password box and a text stating that they should return the phone. If they tap on the Home button a sound will alert you that you should take back your device and will optionally lock your device!
There are two versions of Focus. The free version will always be able to handle photos with the best security possible. The paid version will always get the new features and new media types. As of today, the paid version can also handle video, notify your Android Wear and let you customize Focus as much as possible. In the not too distant future, the paid version will also support web pages!

Get the free versionGet the paid version
- Handles Images only
- Plays sound when user leaves app
- Locks screen if user taps Home button
- All the free features
- Handles Videos
- Notifications to Wear devices
- Change 'return to user' message
Get it on Google Play Get it on Google Play
Here are some links to help you get the most out of Focus. May it be asking questions, following the development or telling us about bugs so that we can fix them right up quick!

Join the Google+ community to ask questions, get the latest news, etc.

REPORT BUGS HERE

Video on setting preferences

Video on how to use Focus

Meta

Architecture: Mike Wallace
Code: Mike Wallace
Visual Design: Mike Wallace

Intro

So, what’s so great about Focus technically?
Class Diagram
Class Diagram
The premises behind Focus are twofold. Android Intents, and media viewing. Although there is nothing special to an Android developer in using Intents, the idea of having an application work solely with Inents is novel. Besides the settings Activity there is no way to interact with Focus besides Intents, and more specifically the sharing Intents. In essence, Focus is a plugin. But more than a plugin to one application, it’s a plugin to any application that can share media.

Focus’ easy of use and simple affordances allow the user to do what they want to do in an easy and intuitive fashion. Focus acts as the user expects: a tap will bring up controls, a double tap will zoom, a swipe will pan the media, a swipe will change to the next media.

And that is where the fun begins.  A bad design would not cater to separation of concerns and bloat the code with ifs and whiles, making future features very difficult to implement. In a good design, all those gestures are to be handled by different components. Bringing up (and hiding) the system controls (the status bar, and navigation bar) is the app’s job, zooming and panning is the ImageView’s job, changing to the next media is the ViewPager’s job, showing media controls is the VideoView’s job. All of this can be done with correct usage of the Android key forwarding and trapping system. When we implement the next feature (web pages) we will only have to create one class and drop it in our framework.

The Image View

The ImageViewFocus class uses ScaleGestureDetector/ScaleListener and GestureDetector/SimpleOnGestureListener to detect the gestures that we want to trap. Scale gestures, double taps, flings, and scrolls are all managed internally, single taps are sent back up to the parent by calling performClick. Zooming and panning is done by using image Matrix and simple mathematics. The tricky part is panning. ImageViewFocus’ first step is to tell it’s parent to stop intercepting touch events (getParent().requestDisallowInterceptTouchEvent(true)). If the image can be panned then ImageViewFocus keeps the TouchEvent and pans the image. If the image cannot be panned then ImageViewFocus will allow the parent to intercept again, at which point the parent will do its job, in this case, page over to the next image. Very simple when done correctly.

The Video View

At first, we thought that the video view would be very simple, just extend VideoView like we did with ImageView. The initial tests worked fine, but then the problems arrived… The first problem was that, no matter what layout attributes we tried, we could not get the video to center on the screen. After much researching, it turns out that the way to fix this is to put the VideoView inside of a FrameLayout, and setting the FrameLayout’s gravity to Gravity.CENTER. I’m not a fan of this extra layout object, but it works.

ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); setLayoutParams(params);

m_videoView = new VideoViewFocus(context, this);

LayoutParams lytprms = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); lytprms.gravity = Gravity.CENTER; m_videoView.setLayoutParams(lytprms);

m_mediaController = new MediaControllerFocus(context); m_videoView.setMediaController(m_mediaController);

addView(m_videoView, lytprms);


The second problem was the system navigation controls did not act correctly. The would disappear at the wrong moment, and we couldn’t figure out why. Turns out that Android implementation of the MediaController uses a floating window of class Window which overrides the ActivityFocusGallery’s window attributes. This is a serious design problem in the Android source code and we had to recode the VideoView class and the MediaController class so that they no longer used the Window class.

The Framework

The framework works thanks to a polymorphic design where the ViewPager must only deal with elements which implement the MediaViewBase interface. The PagerAdapter only has to call getViewForURI on the MediaViewManager class, which will return the correct class for the URI that is to be viewed. Adding future media types is a snap.