Selasa, 09 September 2014

won-tube youtube downloader

Free YouTube Downloader for Android

Forget about annoying issues like connectivity, coverage related, data streaming or low Internet speed from now on. Download YouTube videos to view offline anywhere.





Free YouTube Downloader for Android


Free YouTube Download

Free for 100% Sure

Free YouTube Downloader for Android users. It is 100% reliable and of course Free. Just have a try now.
Free YouTube Download

Download YouTube Video

The best way to watch YouTube Video is to download it. With this simple and trouble-free application, never mind about buffering issues and your favorite video is deleted by the author.





Searches related to 



wontube youtube downloader won tube downloader you tube downloader youtube downloader android umile youtube downloader youtube mate download for android tubemate android tubemate tubemate download Searches related to won tube downloader won tube downloader for android tube downloader android tube downloader online tube downloader for pc all tube downloader tube downloader for mac tube downloader for chrome you tube downloader Searches related to won tube downloader for android max tube downloader for android android market won download android won download pictures tubemate youtube downloader for android tube downloader android apk easy tube downloader for android you tube downloader android tube downloader android tutorial
Read More..

TubeMate YouTube Downloader






INSTALL APP


Summary: You can download the various quality of video from YouTube, from 3gp to Full-HD

Updated: Sep 3, 2014
Found in: multimedia, youtube, video, mp3, movie, download


Downloads: 25292598
What is TubeMate YouTube Downloader:
[TubeMate - The fastest and most famous YouTube downloader]

Visit http://tubemate.net to get more information
[The original fast download technology]
* Fast download mode(with multiple connections for a download)
* Multiple download resolution options
* Background, multi-download
* Resume downloading
* Convert to MP3 (powered by MP3 Media Converter)
* Playlist as video/audio(powered by Meridian Player)
* Share your video finds via Google Buzz, Twitter or e-mail at the tap of a button
* YouTube search and related videos suggestions
* Save favorite videos to your YouTube account, create playlists

TubeMate YouTube Downloader enables you to quickly access, search, share, and download YouTube videos. Because downloading always happens in the background, you can go on watching YouTube, surfing the Internet, tweeting, and listening to your music as you download.

[Available resolutions]
1920x1080(Full-HD): GalaxyTab, Galaxy S2, PC
1280x720(HD): high-end devices
640x360: general devices
320x240: low-end devices
640x360, 854x480(FLV) : Android 2.1 and over
(the available options depend on the quality of the uploaded video and your device)


Terms Of Use : TubeMate must only be used for private purposes. Any commercial use of TubeMate is strictly forbidden and will be pursued in a court of law.










Searches related to 



TubeMate YouTube Downloader tubemate youtube downloader android market tubemate youtube downloader application tubemate youtube downloader apk download tubemate youtube downloader for pc tubemate youtube downloader for pc free download tubemate youtube downloader app tubemate youtube downloader for laptop tubemate youtube downloader for windows Searches related to tubemate youtube downloader application tubemate youtube downloader free free download youtube downloader for android mobile free youtube downloader for phone you tube downloader application youtube downloader for android Searches related to free download youtube downloader for android mobile tubemate youtube downloader for android 2.2 free download how to download youtube videos on android phone tubemate for android 2.2 free download android app to download youtube videos android market tubemate youtube downloader application youtube downloader apk download tubemate for android umile youtube downloader tubemate youtube downloader for pc
Read More..

Jumat, 29 Agustus 2014

Getting Started with Android L Animations

    Among many other new features, Android L has brought a slew of new animations that can be added to your apps. In this post I will go over some of those new animations and how to implement them into an app. All of the code for this post can be found on GitHub.

Ripples and Accents


    Android now supports a handful of predefined style attributes that relate to specific parts of the app, such as the status bar or navigation bar. This new system gives us an easy way to introduce two very simple, yet useful, animations: ripples and accented UI widgets. Ripples are the preferred way of giving users feedback from their actions on UI elements, and their color can be set by applying a color value to the colorControlHighlight attribute in your app theme.

<item name="android:colorControlHighlight">#0000AA</item>



    Just as easily, UI widgets, such as checkboxes, can be set using the colorAccent property in your styles folder to give them a color that fits with your app theme without having to use a set of different  images and state drawables.

<item name="android:colorAccent">#00FF00</item>


Circular Reveal


    One common task in Android is changing the visibility of an element on the screen. Using a ValueAnimator, developers now have an extra option for making this task stand out a bit more: the circular reveal. This can be used by using the ViewAnimationUtil.createCircularReveal method, and then changing the visibility of your view at the appropriate time using an animation listener. Here are the two very similar methods used for making a view visible or gone. Note that the reveal method has a duration set, causing it to take a second to finish the animation, whereas the hide animation is a lot faster. The getX() and getY() methods simply return the center points of the image along its given X and Y axes, and getRadius() simply returns the width of the view.

private void hideImageCircular() {
int x = getX();
int y = getY();
int radius = getRadius();

ValueAnimator anim =
ViewAnimationUtils.createCircularReveal(mImageView, x, y, radius, 0);

anim.addListener(new AnimatorListenerAdapter() {

@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
mImageView.setVisibility( View.INVISIBLE );
}
});

anim.start();
}

private void revealImageCircular() {
int x = getX();
int y = getY();
int radius = getRadius();

ValueAnimator anim =
ViewAnimationUtils.createCircularReveal(mImageView, x, y, 0, radius);

anim.setDuration( 1000 );
anim.addListener( new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
super.onAnimationStart(animation);
mImageView.setVisibility( View.VISIBLE );
}
});

anim.start();
}


Activity Transitions


    In addition to the previous animations, Android L added a few stock activity transition animations to help make apps look and feel more polished - explode, slide and fade. In order to use these transitions, you must request the content transitions feature in both your entering and exiting activities before setting your content view.

getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS);

    While setting transitions through a style is supported, for this case I will go over how to set transitions in the activities. Simply use the getWindow().setExitTransition( Transition ) and getWindow().setEnterTransition( Transition ) methods to tell your activities how to act when opening and closing. In the case of the explode transition, the code for going from MainActivity and our ListFragment to the second activity will look like this:

ListFragment:
getActivity().getWindow().setExitTransition( new Explode() );
intent = new Intent( getActivity(), ExplodeAnimationActivity.class );
startActivity( intent );

ExplodeAnimationActivity:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS);
getWindow().setEnterTransition( new Explode() );
getWindow().setExitTransition( new Explode() );
setContentView(R.layout.activity_explode_animation);
}

@Override
public void onBackPressed() {
super.onBackPressed();
finishAfterTransition();
}

    Notice the onBackPressed method - this is important because it lets the OS know that the animation should finish before it hides the calling second activity. Using these few simple lines of code, we have our three types of simple activity transitions:
Explode Transition

Slide Transition

Fade Transition

    One useful tool that I am not using, but definitely deserves mentioning, is the Transition.TransitionListener. Applying this to your enter or exit transition allows for performing tasks at different points in the animation lifecycle, giving you more control over how your app should act. This listener should also be removed in onDestroy in order to prevent a leak.

getWindow().getEnterTransition().addListener( new Transition.TransitionListener {
@Override
public void onTransitionStart(Transition transition) {

}

@Override
public void onTransitionEnd(Transition transition) {

}

@Override
public void onTransitionCancel(Transition transition) {

}

@Override
public void onTransitionPause(Transition transition) {

}

@Override
public void onTransitionResume(Transition transition) {

}
});


Shared Element Activity Transitions


    On top of the standard activity transitions, it is now possible to support animating shared elements across two activities. The first thing that has to be done to support this is setting your activity to use content transitions and allow overlapping transitions. This can be done through the style applied to your activities:

<item name="android:windowContentTransitions">true</item>
<item name="android:windowAllowEnterTransitionOverlap">true</item>
<item name="android:windowAllowExitTransitionOverlap">true</item>

    While shared element transitions can be applied in Java, for this example I will use styles to apply the shared element transitions:

<item name="android:windowSharedElementEnterTransition">@transition/changebounds</item>
<item name="android:windowSharedElementExitTransition">@transition/changebounds</item>

    where the changebounds transition is defined as an xml file in our resources folder. Notice that I added two additional properties, duration and interpolator, in order to make the animation a little more fun.

changebounds.xml:
<changeBounds

xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="1000"
android:interpolator="@android:interpolator/bounce" />

    The next step is to make sure you have a comparable view type (in this case we'll use ImageView) in both of your activity layouts, and that they both must have the same viewName attribute value. In our first activity, the view that will have the shared element will look like this:

<ImageView
android:id="@+id/image"
android:viewName="image"
android:layout_width="match_parent"
android:layout_height="250dp" />

    and the view in the second activity will look like this:

<ImageView
android:id="@+id/image"
android:layout_alignParentBottom="true"
android:viewName="image"
android:layout_width="match_parent"
android:layout_height="250dp" />

    Now that all of the xml setup is ready to go, we can start coding in the transition from our activities. In the first activity, we set the transition group for the parent container view to false, and then take the drawable from the imageview that we want to share and compress and convert it into a byte stream that can be stored in an intent bundle. We then create ActivityOptions with a scene transition animation for our imageview and start the next activity.

Intent intent = new Intent( this, SharedElementSecondAnimationActivity.class );

((ViewGroup) mImageView.getParent()).setTransitionGroup( false );

ByteArrayOutputStream stream = new ByteArrayOutputStream();
( (BitmapDrawable) mImageView.getDrawable() ).getBitmap().compress(Bitmap.CompressFormat.PNG, 100, stream);
intent.putExtra( "image", stream.toByteArray() );

ActivityOptions options;

try {
options = ActivityOptions.makeSceneTransitionAnimation( this, mImageView, "image" );
} catch( NullPointerException e ) {
Log.e( "SharedElementAnimationChangeBoundsActivity", "Did you set your ViewNames in the layout file?" );
return;
}

if( options == null ) {
Log.e("sharedelementanimation", "Options is null. Something broke. Good luck!");
} else {
startActivity(intent, options.toBundle());
}

    In the second activity, we read the byte array from the intent bundle and decode it into a bitmap. We then apply that bitmap to an imageview. This second activity also has the onBackPressed method with finishAfterTransition in order to apply the transition when hitting the back button.

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_shared_element_second_animation);
mImageView = (ImageView) findViewById( R.id.image );

byte[] byteArray = getIntent().getByteArrayExtra("image");
Bitmap bitmap = BitmapFactory.decodeByteArray(byteArray, 0, byteArray.length);
mImageView.setImageBitmap(bitmap);
}

@Override
public void onBackPressed() {
super.onBackPressed();
finishAfterTransition();
}

    And with that we now have a shared element transition that moves our shared element to its new location in the second activity, and has an extra bounce effect:


    These few examples of animations only begin to scratch the surface of what's possible in Android L, not to mention the scene transitions that were introduced in Kit Kat. I hope this tutorial helps other developers get started with the new possibilities, as applying animations makes for beautiful apps that are also fun to work on.

Read More..

Jumat, 22 Agustus 2014

Programmatically Coloring Drawables

    With the introduction of Android L, developers now have an easy way to change the color of drawables to match the theme of their app. Despite this, many developers will need to support earlier Android versions in their apps, so I have decided to share a technique for changing drawable asset colors using Picasso for both local and remote assets. The source code for this example can be found on GitHub.

    The key to this technique is using the Transform interface provided in the Picasso library, which provides a transform method to take a bitmap and return an altered bitmap for use in the Picasso image loading method. This interface can be useful for things like changing the size of an image, or in this case changing the image color. The ColorTransformation class that we will use in this example implements the Transform interface and can either accept a color value in its constructor, or have a color set from a resource value.

public ColorTransformation( int color ) {
setColor( color );
}

public void setColor( int color ) {
this.color = color;
}

public void setColorFromRes( Context context, int colorResId ) {
setColor( context.getResources().getColor( colorResId ) );
}

    The transform method is where the magic happens. We provide a source bitmap (which is passed to the transform by Picasso automagically in its drawable building process) and return an altered version. In this example we create a new drawable from the source bitmap in order to get the dimensions of the image, then create a new bitmap and canvas for that bitmap. We then set the bounds for the drawable and apply a color filter using the SRC_IN version of the PorterDuff algorithm - applying the color on top of the visible portions of the drawable ( if you haven't read up on PorterDuff, it's definitely a worth while and interesting topic ) and then draw the altered drawable onto the canvas of the new bitmap before returning it. We also recycle the source bitmap once it is no longer needed per best practices for managing memory with Bitmaps in 2.3 and lower Android devices.

@Override
public Bitmap transform(Bitmap source) {
if( color == 0 ) {
return source;
}

BitmapDrawable drawable = new BitmapDrawable(Resources.getSystem(), source );
Bitmap result = Bitmap.createBitmap( drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888 );
Canvas canvas = new Canvas( result );
drawable.setBounds( 0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight() );
drawable.setColorFilter( color, PorterDuff.Mode.SRC_IN );
drawable.draw(canvas);
drawable.setColorFilter(null);
drawable.setCallback(null);

if( result != source ) {
source.recycle();
}

return result;
}

    One additional point to notice in the ColorTransformation class is that there is a key method provided. This is used by Picasso for retaining transformed drawables in memory, allowing for quicker loading when a drawable is transformed and displayed multiple times, such as in a listview.

@Override
public String key() {
return "DrawableColor:" + color;
}

    Now that the transform class is built, we can use it to load drawables in our app with specific colors. In MainActivity I have four image views: one that uses an unaltered local drawable, one that loads in and transforms a local drawable, one that loads in an unaltered asset through a URL and one that loads in the same asset via URL, but applies a transform to change its color. The latter three imageviews have their drawables populated like so:

Picasso.with( this )
.load( R.drawable.ic_star )
.transform( new ColorTransformation(getResources().getColor( R.color.local_drawable_color ) ) )
.into( mDrawableTransformedImage );

Picasso.with( this )
.load( getString( R.string.image_url ) )
.into( mDrawableUrlImage );

Picasso.with( this )
.load( getString( R.string.image_url ) )
.transform( new ColorTransformation( getResources().getColor( R.color.remote_image_color ) ) )
.into( mDrawableUrlTransformedImage );

    As you can see, the ColorTransform class is created for each drawable and a color is passed to it, and Picasso handles the rest by calling Transform and dealing with memory management/caching behind the scenes. The last part of MainActivity uses a Picasso Target to load a drawable into an object that has callbacks associated with it. This technique is used for colorizing and placing an image into the action bar, as the Picasso.into method does not work with the action bar icon directly. First we declare our Target and the actions it should perform with its drawable once it has been loaded or if it fails:

private Target ActionBarIconTarget = new Target()
{
@Override
public void onBitmapLoaded( Bitmap bitmap, Picasso.LoadedFrom from )
{
getSupportActionBar().setIcon( new BitmapDrawable( getResources(), bitmap ) );
}

@Override
public void onBitmapFailed( Drawable errorDrawable )
{
getSupportActionBar().setIcon( R.drawable.ic_launcher );
}

@Override
public void onPrepareLoad( Drawable placeHolderDrawable )
{

}
};

    Once we have our target and what it should do defined, we can load our altered drawable into the target so that the image can be loaded into the action bar.

Picasso.with( this )
.load( R.drawable.ic_star )
.transform( new ColorTransformation( getResources().getColor( R.color.action_bar_icon_color ) ) )
.into( ActionBarIconTarget );

    And with that we now have an easy way to load recolored drawables across our app without generating new assets in each color. This is particularly useful when applying techniques like my last post on using Gradle to reskin the same code base for multiple applications. Below I have provided an image from the demo app showing the same icons in various colors after being run through this code. Hopefully it will help you other developers out there save a fair bit of time.

The unaltered URL drawable may be a bit hard to see, but it's originally a black icon of the Android logo

Read More..

Minggu, 03 Agustus 2014

    The Android framework allows for customization of apps based on different attributes of a physical device through the structuring of an apps resource folders, letting a developer change things such as layouts, integers and string values in order to fit their apps needs for a given device. Using this, developers can easily change configurations between phones, small and large tablets, and devices in landscape or portrait mode. With the introduction of Gradle and Android Studio, the ability to use folder structures has been expanded to allow for overriding resource folders and values per different product flavors and build types, such as debug and release. In this tutorial I will go over using Gradle to reskin a base application using product flavors. All source code can be found on GitHub.

    To start, let's touch on using resource values in an application. If you append a quantifying value such as -xxhdpi, -land or -sw600dp to a resource folder, then the resource values in those folders will override the values in their main counterpart folder for devices that fit the appended values criteria. This means that if a device is in landscape mode, it will use resources from values-land over those in values if available, and if the device is at least a small tablet, then items in values-sw600dp will take precedence.

    The differences here can be seen in the following example screen shot, where one line of text is changed depending on the default value (for portrait devices) and the values-land string value. Without any code changes, the device will choose which string value to use based on the orientation of the phone.
default orientation string - portrait
landscape orientation string on a Nexus 4

    Now that we have a base understanding of resource hierarchies in the Android framework, let's move on to the overall goal of this tutorial - reskinning an app using product flavors. This is done almost entirely in the build.gradle file, though there will be some additions in the project folder structure. A default Android application in Android Studio will already come with the build type node populated for debug and release.

buildTypes {
release {
//This is where the signing cert would be referenced for the release build
}
debug {
//This is where the signing cert would be referenced for the debug build
}
}

    Under the buildTypes node, we can define the main categories of product flavors that we will want to use. When generating a project, one type of each of these flavors will be used, as well as one of the build types.

flavorDimensions "color", "number"

    Once the types of flavor dimensions are defined, we can start declaring types of product flavors and assigning them to a flavor dimension.

productFlavors {
blue {
applicationId "com.ptrprograms.gradleproductflavorsblue"
flavorDimension "color"
}
green {
applicationId "com.ptrprograms.gradleproductflavorsgreen"
flavorDimension "color"
}
orange {
applicationId "com.ptrprograms.gradleproductflavorsorange"
flavorDimension "color"
}
purple {
applicationId "com.ptrprograms.gradleproductflavorspurple"
flavorDimension "color"
}
red {
applicationId "com.ptrprograms.gradleproductflavorsred"
flavorDimension "color"
}
yellow {
applicationId "com.ptrprograms.gradleproductflavorsyellow"
flavorDimension "color"
}

one {
flavorDimension "number"
}

two {
flavorDimension "number"
}
}

    Note that each of the color flavors has an applicationId value set. This allows us to differentiate between our products, getting multiple reskinned applications onto the Play Store with the same code base. With the product flavors defined, we can now use the Build Variants window in Android Studio to pick a mix of build types and product flavors to install or build.


    Similar to overriding values within one application by device size or orientation, we can also override values by product flavor. By creating directories in the same folder as 'main' titled after their product flavors, the resources in those directories will take precedence over the main resource values. In this example I override all of the launcher icons, the background color resource and a few strings matching the product flavor in each of the color flavors. Likewise I override a string in the number product flavor directories.



    With these values filled out, we can quickly generate similar apps with cosmetic changes, as can be seen from the blue version of the app at the beginning of this post and this green product running on a Nexus 7.

    And with that we are able to generate many different applications using a similar code base with different values per product for colors, images, text and any other available type of resource, so that multiple apps can be built quickly with just some planning and organization.

Read More..

Sabtu, 19 Juli 2014

Creating a Media App for AndroidTV

    One of the newest technologies released by Google this year at I/O is the AndroidTV, a platform that takes what they learned from the Chromecast and Google TV and makes it even better by building on the Android OS. For this tutorial I will go over putting together a basic media app for the AndroidTV in order to help other developers get their own apps and content out for this platform in order to push for its success. While the base Android project from Android Studio does let you create a media app, it provides far more than the basics and needs a lot of clean up, so I went ahead and did that clean up and will go over the different methods used in order to hopefully provide some clarity. While I happened to have received my AndroidTV ADT-1 developer box at I/O by luckily sitting in on the session, other developers can request a kit through Google's site. The source code for this project can be found on GitHub.

    The first thing we need to do in a new Android project is set up our gradle file. AndroidTV is currently using the Android-L SDK and has dependencies on the new support library for leanback, recyclerview, and appcompat, then third party libraries used are GSON and Picasso

android {
compileSdkVersion 'android-L'
buildToolsVersion "20.0.0"
}

dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:recyclerview-v7:+'
compile 'com.android.support:leanback-v17:+'
compile 'com.android.support:appcompat-v7:+'
compile 'com.squareup.picasso:picasso:2.3.2'
compile 'com.google.code.gson:gson:2.2.4'
}

    Next we need to set up our manifest to use the Internet permission and know what activities we will use in the project. The main two activities for this project are the MainActivity and PlayerActivity, though I also include Bonus.SlothActivity, which I added to this project to play around with creating a custom activity and decided to leave in the app to show that you can use any activity on this platform (I'll go over this at the end, since I had fun with it). Note that the category the the MainActivity intent-filter is leanback_launcher, as this is what allows the app icon to show up on the television.

<uses-permission android:name="android.permission.INTERNET" />
<uses-feature
android:name="android.hardware.touchscreen"
android:required="false" />

<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".Activity.MainActivity"
android:label="@string/app_name"
android:logo="@drawable/giraffes"
android:screenOrientation="landscape" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LEANBACK_LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".Activity.PlayerActivity"
android:theme="@android:style/Theme.NoTitleBar.Fullscreen" />
<activity android:name=".Activity.DetailsActivity" />

<activity
android:name=".Bonus.SlothActivity"
android:theme="@android:style/Theme.NoTitleBar.Fullscreen" />

</application>

    Under our styles file, we need to set AppTheme to extends the Leanback theme, otherwise the app will not load, however it's still not certain if this will be the case when Android L and AndroidTV officially launch.

<style name="AppTheme" parent="@style/Theme.Leanback">

    Now that the general configuration is set, we should be able to start moving into the actual java code. MainActivity is simply a base activity with a layout that contains a fragment, so we'll put together the layout for now and then jump into how MainFragment works.

public class MainActivity extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}


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

xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main_browse_fragment"
android:name="com.ptrprograms.androidtvmediaplayer.Fragment.MainFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
tools:deviceIds="tv"
tools:ignore="MergeRootFrame" />


    MainFragment.java extends the new BrowseFragment provided in the support library, which gives us a lot of the functionality we need for a media app such as the fast lane (side navigation bar) and view for the rows of content. The only member variable that we'll need here is a List of Movie objects, where Movie is just a standard serialized model object containing information about a movie like the title, category, description and URLs to associated images and the video.

public class Movie implements Serializable {
private String title;
private String description;
private String studio;
private String videoUrl;
private String category;
private String cardImageUrl;
private String backgroundImageUrl;
...

    The first thing that MainFragment does in onActivityCreated is load the data for the list of Movie objects. In this case I'm simply using a locally stored JSON file and converting it into the list using GSON, but this method can be used however works for your project to load in data, be it locally or from an online API.

private void loadData() {
String json = Utils.loadJSONFromResource( getActivity(), R.raw.movies );
Gson gson = new Gson();
Type collection = new TypeToken<ArrayList<Movie>>(){}.getType();
mMovies = gson.fromJson( json, collection );
}

   Next we can go ahead and initialize the base UI by setting the title in the top right of the screen, enabling category headers, setting the action the back button on the remote should take (opening the fast lane or returning to the home screen), setting fragment colors and background. I should mention that I only set the background once in MainFragment, however one set of polish that you can add to your app is changing the background whenever a new item is selected in order to match the selected item. Also, there is a method built into BrowseFragment called setBadgeDrawable which lets you pass a drawable resource id to display an image in the top right corner rather than plain text.

private void initUI() {
setTitle( getString( R.string.browse_title ) );
setHeadersState( HEADERS_ENABLED );

//Back button goes to the fast lane, rather than home screen
setHeadersTransitionOnBackEnabled( true );

setBrandColor( getResources().getColor( R.color.fastlane_background ) );
setSearchAffordanceColor( getResources().getColor( R.color.search_button_color ) );
setBackground();
}

Example of the fast lane with background color, search circle with background color and title text. I stuck with a black/grey theme, which may not be the best for examples, but was far easier on my eyes without having to be great at design :)
    After our colors and base UI are set, we can start populated data in order to get the categories in the fast lane and cards that you see in the image above. We do this by creating a new adapter of ListRowPresenters to hold the rows, then create sets of ListRows containing our cards to put into that adapter (think linked list of linked lists) before assigning the adapter of ListRows to the fragment, similar to using setAdapter in a ListFragment. For this method each row will consist of cards representing Movie objects from the same category - comedy, horror, or action.

private void loadRows() {

ArrayObjectAdapter rowsAdapter = new ArrayObjectAdapter( new ListRowPresenter() );
CardPresenter cardPresenter = new CardPresenter();

List<String> categories = getCategories();
if( categories == null || categories.isEmpty() )
return;

for( String category : categories ) {
ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter( cardPresenter );
for( Movie movie : mMovies ) {
if( category.equalsIgnoreCase( movie.getCategory() ) )
listRowAdapter.add( movie );
}
if( listRowAdapter.size() > 0 ) {
HeaderItem header = new HeaderItem( rowsAdapter.size() - 1, category, null );
rowsAdapter.add( new ListRow( header, listRowAdapter ) );
}
}

setupPreferences( rowsAdapter );
setAdapter( rowsAdapter );

}

    As you can see in the second loop, for each movie we check to see if the movie category matches the current row category, and if it does we add it to our adapter of CardPresenter objects. The CardPresenter extends the Presenter class to bind our movie object to a programmatically created view and also implements the ViewHolder pattern. The main methods for the card presenter are shown here and are from CardPresenter.java

static class ViewHolder extends Presenter.ViewHolder {
private ImageCardView mCardView;
private PicassoImageCardViewTarget mImageCardViewTarget;

public ViewHolder( View view ) {
super( view );
mCardView = (ImageCardView) view;
mImageCardViewTarget = new PicassoImageCardViewTarget( mCardView );
}

public ImageCardView getCardView() {
return mCardView;
}

protected void updateCardViewImage( Context context, String link ) {
Picasso.with( context )
.load(link)
.resize( mCardView.getResources().getInteger( R.integer.card_presenter_width ), mCardView.getResources().getInteger( R.integer.card_presenter_height ) )
.centerCrop()
.error( R.drawable.default_background )
.into( mImageCardViewTarget );
}
}

@Override
public ViewHolder onCreateViewHolder(ViewGroup parent) {
ImageCardView cardView = new ImageCardView( parent.getContext() );
cardView.setFocusable( true );
cardView.setFocusableInTouchMode( true );
return new ViewHolder(cardView);
}

@Override
public void onBindViewHolder(Presenter.ViewHolder viewHolder, Object item) {
Movie movie = (Movie) item;

if ( !TextUtils.isEmpty( movie.getCardImageUrl() ) ) {
((ViewHolder) viewHolder).mCardView.setTitleText( movie.getTitle() );
((ViewHolder) viewHolder).mCardView.setContentText( movie.getStudio() );
((ViewHolder) viewHolder).mCardView.setMainImageDimensions(
( (ViewHolder) viewHolder ).mCardView.getContext().getResources().getInteger( R.integer.card_presenter_width ),
( (ViewHolder) viewHolder ).mCardView.getContext().getResources().getInteger( R.integer.card_presenter_height ) );
( (ViewHolder) viewHolder ).updateCardViewImage( ( (ViewHolder) viewHolder ).getCardView().getContext(), movie.getCardImageUrl() );
}
}

Switching between rows using the fast lane
Example of the cards full view in a row with their category header
    Returning to our loadRows method in MainFragment.java, we have a method called setupPreferences. All this does is low another row at the end of our rows adapter that contains a PreferenceCardPresenter (similar to the CardPresenter class above, but greatly simplified to just display text in a square). I'm only adding one preference here as an example.

private void setupPreferences( ArrayObjectAdapter adapter ) {

HeaderItem gridHeader = new HeaderItem( adapter.size(), "Preferences", null );
PreferenceCardPresenter mGridPresenter = new PreferenceCardPresenter();
ArrayObjectAdapter gridRowAdapter = new ArrayObjectAdapter( mGridPresenter );
gridRowAdapter.add( getResources().getString( R.string.sloth ) );
adapter.add( new ListRow( gridHeader, gridRowAdapter ) );

}


    The final thing that we need to do once MainActivity/MainFragment are created is initialize our event listeners. The search button in BrowseFragment has a special method for this called setOnSearchClickedListener, however I will leave implementing search for another post. The other event listener that needs to be set is the BrowseFragment's setOnItemClickedListener like so

private void setupEventListeners() {
setOnItemClickedListener( getDefaultItemClickedListener() );
setOnSearchClickedListener( new View.OnClickListener() {
@Override
public void onClick(View view) {
Toast.makeText(getActivity(), "Implement your own in-app search", Toast.LENGTH_LONG).show();
}
});
}

    where the default item clicked listener checks to see if the data item is a Movie object, and if it is then it packages it into an intent to launch the DetailsActivity which simply houses VideoDetailsFragment. If it is a string, then we know it belongs to our Preference row (though we could just as easily have created a special Preference object to populate that row) and we launch the SlothActivity that I will show later.

protected OnItemClickedListener getDefaultItemClickedListener() {
return new OnItemClickedListener() {
@Override
public void onItemClicked( Object item, Row row ) {
if( item instanceof Movie ) {
Movie movie = (Movie) item;
Intent intent = new Intent( getActivity(), DetailsActivity.class );
intent.putExtra( VideoDetailsFragment.EXTRA_MOVIE, movie );
startActivity( intent );
} else if( item instanceof String ) {
if( ((String) item).equalsIgnoreCase( getString( R.string.sloth ) ) ) {
Intent intent = new Intent( getActivity(), SlothActivity.class );
startActivity( intent );
}
}
}
};
}

    The VideoDetailsFragment extends the new DetailsFragment class and provides a quick overview of a media object with options for the user to select. The first thing we do in this fragment is retrieve the Movie object from the intent that started the DetailsActivity and set up the background for the activity using Picasso from the Movie's background URL property

private void initBackground() {
BackgroundManager backgroundManager = BackgroundManager.getInstance(getActivity());
backgroundManager.attach(getActivity().getWindow());
mBackgroundTarget = new PicassoBackgroundManagerTarget( backgroundManager );

mMetrics = new DisplayMetrics();
getActivity().getWindowManager().getDefaultDisplay().getMetrics(mMetrics);

if( mSelectedMovie != null && !TextUtils.isEmpty( mSelectedMovie.getBackgroundImageUrl() ) ) {
try {
updateBackground(new URI(mSelectedMovie.getBackgroundImageUrl()));
} catch (URISyntaxException e) { }
}
}

protected void updateBackground(URI uri) {
if( uri.toString() == null ) {
try {
uri = new URI("");
} catch( URISyntaxException e ) {}
}

Picasso.with(getActivity())
.load( uri.toString() )
.error( getResources().getDrawable( R.drawable.default_background ) )
.resize( mMetrics.widthPixels, mMetrics.heightPixels )
.into( mBackgroundTarget );
}

    Next we use an AsyncTask to create the DetailsOverviewRow and assign the selected Movie object to it, populate information and set up our actions (the buttons at the bottom of the details card) to do their jobs. In this case I only have one action, and it sends an intent to the PlayerActivity in order to play the selected item.

@Override
protected DetailsOverviewRow doInBackground( Movie... movies ) {
mSelectedMovie = movies[0];
DetailsOverviewRow row = null;
try {
row = new DetailsOverviewRow( mSelectedMovie );
Bitmap poster = Picasso.with( getActivity() )
.load( mSelectedMovie.getCardImageUrl() )
.resize(Utils.dpToPx( getActivity().getResources().getInteger( R.integer.detail_thumbnail_square_size ), getActivity().getApplicationContext() ),
Utils.dpToPx( getActivity().getResources().getInteger( R.integer.detail_thumbnail_square_size ), getActivity().getApplicationContext() ) )
.centerCrop()
.get();
row.setImageBitmap( getActivity(), poster );
} catch ( IOException e ) {
getActivity().finish();
return null;
} catch( NullPointerException e ) {
getActivity().finish();
return null;
}

row.addAction( new Action( ACTION_WATCH, getResources().getString(
R.string.watch ), getResources().getString( R.string.watch_subtext) ) );

return row;
}

@Override
protected void onPostExecute(DetailsOverviewRow detailRow) {
if( detailRow == null )
return;

ClassPresenterSelector ps = new ClassPresenterSelector();
DetailsOverviewRowPresenter dorPresenter =
new DetailsOverviewRowPresenter( new DetailsDescriptionPresenter() );
// set detail background and style
dorPresenter.setBackgroundColor( getResources().getColor( R.color.detail_background ) );
dorPresenter.setStyleLarge( true );
dorPresenter.setOnActionClickedListener( new OnActionClickedListener() {
@Override
public void onActionClicked( Action action ) {
if (action.getId() == ACTION_WATCH ) {
Intent intent = new Intent( getActivity(), PlayerActivity.class );
intent.putExtra( EXTRA_MOVIE, mSelectedMovie );
intent.putExtra( EXTRA_SHOULD_AUTO_START, true );
startActivity( intent );
}
}
});

ps.addClassPresenter( DetailsOverviewRow.class, dorPresenter );
ps.addClassPresenter( ListRow.class,
new ListRowPresenter() );


ArrayObjectAdapter adapter = new ArrayObjectAdapter( ps );
adapter.add( detailRow );
loadRelatedMedia( adapter );
setAdapter( adapter );
}



    Notice the loadRelatedMedia method in onPostExecute. This method is used to (you guessed it) load related media onto the details screen. The only thing I'm doing in this method is extracting all of the movies of the same category as the selected movie from the Movies List and displaying them using the CardPresenter presenter from MainFragment, though more appropriate related movies can be gathered or media apps that have that logic in place.

private void loadRelatedMedia( ArrayObjectAdapter adapter ) {

String json = Utils.loadJSONFromResource( getActivity(), R.raw.movies );
Gson gson = new Gson();
Type collection = new TypeToken<ArrayList<Movie>>(){}.getType();
List<Movie> movies = gson.fromJson( json, collection );
List<Movie> related = new ArrayList<Movie>();
for( Movie movie : movies ) {
if( movie.getCategory().equals( mSelectedMovie.getCategory() ) ) {
related.add( movie );
}
}

if( related.isEmpty() )
return;

ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter( new CardPresenter() );
for( Movie movie : related ) {
listRowAdapter.add( movie );
}

HeaderItem header = new HeaderItem( 0, "Related", null );
adapter.add( new ListRow( header, listRowAdapter ) );
}



    The final important part to a base media project is the actual video player. In this case all of that logic is handled by PlayerActivity.java (which I took from the Android sample app, rather than writing my own, though I do have a post on making a native video player from a few months ago that isn't as great as the Android sample player) and there isn't anything too out of the norm for a video player in this class. The most important part of this video player is the addition of a onKeyDown method that listens for input from the remote control dpad for controlling playback:

@Override
public boolean onKeyDown( int keyCode, KeyEvent event ) {
int currentPos = 0;
int delta = mDuration / getResources().getInteger( R.integer.scrub_segment_divisor );
if ( delta < getResources().getInteger( R.integer.min_scrub_time ) )
delta = getResources().getInteger( R.integer.min_scrub_time );

if ( mControllers.getVisibility() != View.VISIBLE ) {
mControllers.setVisibility( View.VISIBLE );
}
switch ( keyCode ) {
case KeyEvent.KEYCODE_DPAD_CENTER:
return true;
case KeyEvent.KEYCODE_DPAD_DOWN:
return true;
case KeyEvent.KEYCODE_DPAD_LEFT:
currentPos = mVideoView.getCurrentPosition();
currentPos -= delta;
if (currentPos > 0)
play(currentPos);
return true;
case KeyEvent.KEYCODE_DPAD_RIGHT:
currentPos = mVideoView.getCurrentPosition();
currentPos += delta;
if( currentPos < mDuration )
play( currentPos );
return true;
case KeyEvent.KEYCODE_DPAD_UP:
return true;
}

return super.onKeyDown(keyCode, event);
}

Let there be lips!
    And with that you can have a pretty solid media app for the AndroidTV. Now that the technical part is done, if you're not interested in some random ridiculousness, you're alright to stop reading now :)

    Still with me? Alright, cool. So earlier I added a preference square item to MainFragment, and when selected it launches an intent to SlothActivity. I wanted to play around with AndroidTV a bit and see if you can throw in a custom activity, and it turns out you can. With a bit of stylized changes to this project from Bakhtiyor Khodjayev from a couple years ago that originally displayed animated snowflakes falling, I threw together a great custom activity of a sloth putting in a hard days work. Sadly recording though ADB doesn't capture audio, and I removed the MP4 from the project because I didn't want the hassle of being busted for more copyright infringement than I'm (probably, who knows?) doing, but the original audio to this was Led Zeppelin's Boogie with Stu. Anywho, for your viewing pleasure, the custom SlothActivity



Read More..

Minggu, 06 Juli 2014

*** Deprecated. Official API has been released, so please use that :) Here's a sample project to replicate this blog's end product: https://github.com/PaulTR/AndroidDemoProjects/tree/master/WatchFaceWithOptions ***

    For this tutorial I will go over creating a custom watch face for the Android Wear. There are rumors that Google will be releasing a watch face builder class, but right now no one is sure when/if that will happen. The point of this tutorial is to be a central place for information on building custom watch faces with the current system, as the information is currently scattered across Reddit and Google+ posts.

    This demo app allows the user to select a school from a list and then displays the time in the corner with the school logo below it. The settings activity for selecting the school is not a requirement for the watch face, as you can choose to only display one type of face, but I included it to show an additional feature. I also removed the mobile activity launcher, as it's not a necessity for the app. The code for this app is available on GitHub.
Watch face for Fresno State
    The first thing that needs to be done is to open up the mobile and wear AndroidManifest.xml files and add the permissions that will be needed for selecting a watch face:

<uses-permission android:name="com.google.android.permission.PROVIDE_BACKGROUND" />
<uses-permission android:name="android.permission.WAKE_LOCK" />

    In the wear AndroidManifest.xml file, add the following properties to the application tag:

<application
android:allowBackup="true"
android:icon="@drawable/bulldog_wallpaper"
android:label="@string/app_name"
android:theme="@android:style/Theme.DeviceDefault" >

    and the following properties to the activity tag for the watch face activity. Note the intent-filter and meta-data tags in the activity section, as those are required for determining if the activity should be selectable as a watch face. I use a general icon for the preview here, but generally a screen shot of the actual watch face (like above) should be used:

<activity
android:name=".WatchFaceActivity"
android:label="@string/app_name"
android:enabled="true"
android:taskAffinity=""
android:allowEmbedded="true"
android:theme="@android:style/Theme.DeviceDefault.NoActionBar" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.google.android.clockwork.home.category.HOME_BACKGROUND" />
</intent-filter>
<meta-data
android:name="com.google.android.clockwork.home.preview"
android:resource="@drawable/bulldog_wallpaper"/>
</activity>

Preview icon for the watch face

    In order to have the list of schools in the application area, we need to have an intent-filter added to the SettingsActivity activity tag:

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

    Once the manifest is put together, we can go ahead and fill in SettingsActivity to display a list of schools and save the selected school in a shared preference. In this example I use an object called SchoolObj that simply loads a list of school names and codes for organizing data:

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate( savedInstanceState );
setContentView( R.layout.activity_settings );
final SchoolObj schools = new SchoolObj();
ListView listView = (ListView) findViewById( R.id.list );
ArrayAdapter<String> adapter = new ArrayAdapter( this, android.R.layout.simple_list_item_1, schools.schoolList );
listView.setAdapter( adapter );
listView.setOnItemClickListener( new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
SharedPreferences pref = getSharedPreferences( WatchFaceActivity.SHARED_PREFERENCE, Context.MODE_PRIVATE );
SharedPreferences.Editor editor = pref.edit();
editor.putString( SHARED_PREFERENCE_SCHOOL, schools.schoolCodeList.get( position ) );
editor.commit();
finish();
}
});
}

List of schools for customizing the watch face
    The final part to this application is the actual watch face activity. In onCreate() we can take a reference to the containing view, the TextClock object and the ImageView where the school logo will be stored. When onResume() is called we to see if SharedPreferences contains a key for a selected school and then set the color of the TextClock, ImageView drawable and background color for the watch face. If the user has just installed the application and has not selected a watch face, we set a default face.

@Override
protected void onResume() {
super.onResume();
SharedPreferences pref = getSharedPreferences( SHARED_PREFERENCE, Context.MODE_PRIVATE );

if( pref.contains( SettingsActivity.SHARED_PREFERENCE_SCHOOL ) ) {
String schoolCode = pref.getString( SettingsActivity.SHARED_PREFERENCE_SCHOOL, "" );
loadSchoolWatchFace( schoolCode );
} else {
mBackground.setImageResource( R.drawable.bulldog_wallpaper );
mClock.setTextColor(getResources().getColor(android.R.color.holo_red_dark));
mContainer.setBackgroundColor(getResources().getColor( android.R.color.white ) );
}
}

    It is important that we set these properties every time that the activity resumes, as we must set the watch face to a "blank state" when the watch is put into a power conserving off state and onPause() is called

@Override
protected void onPause() {
super.onPause();
mBackground.setImageDrawable( null );
mClock.setTextColor( getResources().getColor( android.R.color.white ) );
mContainer.setBackgroundColor( getResources().getColor( android.R.color.black ) );
}

Watch Blank State
    The loadSchoolWatchFace( schoolCode ) method simply checks the school code in a set of if/else statements to set the proper image and colors, just like the default else portion of onResume()

private void loadSchoolWatchFace( String schoolCode ) {
if( "cuboulder".equals( schoolCode ) ) {
mBackground.setImageResource( R.drawable.cuboulder_wallpaper );
mClock.setTextColor(getResources().getColor(android.R.color.holo_orange_light));
} else if( "fsu".equals( schoolCode ) ) {
mBackground.setImageResource( R.drawable.floridastate_wallpaper );
mClock.setTextColor(getResources().getColor(android.R.color.holo_red_dark));
} else if( "ucsc".equals( schoolCode ) ) {
mBackground.setImageResource( R.drawable.bananaslugs_logo );
mClock.setTextColor(getResources().getColor(android.R.color.holo_orange_light));
} else if( "berkeley".equals( schoolCode ) ) {
mBackground.setImageResource( R.drawable.berkeley_wallpaper );
mClock.setTextColor(getResources().getColor(android.R.color.holo_orange_light ) );
} else {
//Default to Fresno
mBackground.setImageResource( R.drawable.bulldog_wallpaper );
mClock.setTextColor(getResources().getColor(android.R.color.holo_red_dark));
}

mContainer.setBackgroundColor(getResources().getColor(android.R.color.white));
}
Florida State University watch face
UC Santa Cruz Banana Slugs watch face

    And that's all there is to it. The important parts to add are the manifest intent-filter and metadata items, and onResume()/onPause() for the watch face, then the rest adds functionality to the app. This can also work with an analog watch face and other views, so there's a lot more possibilities for developers to add some great features.


Read More..