We launched In-app Billing on Google Play a year ago to give developers more ways to sell and engage users over the lifetime of their apps. Since the launch, In-app Billing has been extremely successful in helping developers monetize their apps through try-and-buy, virtual goods, upgrades, and other popular business models. Today, 23 of the 24 top-grossing apps in Google Play use In-app Billing, and the total revenue generated from in-app purchases exceeds revenue from traditional app purchases.
We’re now taking In-app Billing further by adding another important business model — subscriptions. Starting today, developers can use In-app Billing to sell monthly or annual subscriptions from inside of their apps. All subscriptions are auto-renewing, for every app and game and every type of subscription product. Developers just set the price and billing interval and Google Play manages the purchase transactions for them, just as it does for other in-app products and app purchases.
For users, Google Play provides a familiar and convenient purchase experience, highlighting subscription details such as price and billing interval before continuing with purchases. After the transaction, Google Play manages recurring billing and keeps users informed of new charges, sending them an email with each renewal. At any time, users can visit My Apps in the Play Store app to view their subscriptions and cancel any subscription as needed.
While making it easy for developers to offer a great purchasing experience, our subscriptions are also designed for flexibility. Developers can use them to monetize premium dynamic content such as journals and magazines, but they can also use them to sell access to bundled products, game levels, music and video content, value-added services, or any other digital content.
Building on Google Play’s strength as a truly cloud-connected experience, developers can offer users the ability to carry their subscriptions across multiple properties, services, or campaigns. To make this easier, we’re introducing an HTTP-based publisher API through which enterprise-scale backend servers can validate or cancel subscriptions. Using this API, for example, developers can extend access from their Android apps to their web properties, based on subscriptions that are purchased on Google Play.
In the coming days, several developers will be launching apps with Google Play subscriptions and we expect many more to follow. Glu Mobile is launching updated versions of its top Android titles, including Frontline Commando, offering subscriptions through custom VIP currency packages. "We're using Google Play subscriptions to offer consumers a compelling value and a single currency which they can use across Glu’s most popular titles” says Niccolo de Masi, CEO of Glu. “We're excited to bring these capabilities to our Android users and we believe that Google Play subscriptions will fuel further growth in our business."
If you’re a developer, you can get started with subscriptions right away by reading the In-app Billing documentation and downloading the updated sample app. If you are already using in-app billing, you’ll find that adding support for subscriptions is straightforward and involves only minor changes to your code.
You can publish your updated apps and subscription products as soon as you are ready. We’ve already rolled out client support to most Android devices worldwide, so any user with Google Play 3.5 or higher installed can buy subscriptions starting today.
We’re looking forward to seeing how you use subscriptions in your apps!
Using DialogFragments
[This post is by David Chandler, Android Developer Advocate — Tim Bray]
Honeycomb introduced Fragments to support reusing portions of UI and logic across multiple activities in an app. In parallel, the showDialog / dismissDialog methods in Activity are being deprecated in favor of DialogFragments.
In this post, I’ll show how to use DialogFragments with the v4 support library (for backward compatibility on pre-Honeycomb devices) to show a simple edit dialog and return a result to the calling Activity using an interface. For design guidelines around Dialogs, see the Android Design site.
The Layout
Here’s the layout for the dialog in a file namedfragment_edit_name.xml
.<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/edit_name"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center" android:orientation="vertical" >
<TextView
android:id="@+id/lbl_your_name" android:text="Your name"
android:layout_width="wrap_content" android:layout_height="wrap_content" />
<EditText
android:id="@+id/txt_your_name"
android:layout_width="match_parent" android:layout_height="wrap_content"
android:inputType=”text”
android:imeOptions="actionDone" />
</LinearLayout>
Note the use of two optional attributes. In conjunction with android:inputType=”text”
, android:imeOptions=”actionDone”
configures the soft keyboard to show a Done key in place of the Enter key.The Dialog Code
The dialog extends DialogFragment, and since we want backward compatibility, we’ll import it from the v4 support library. (To add the support library to an Eclipse project, right-click on the project and choose Android Tools | Add Support Library...).import android.support.v4.app.DialogFragment;
// ...
public class EditNameDialog extends DialogFragment {
private EditText mEditText;
public EditNameDialog() {
// Empty constructor required for DialogFragment
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_edit_name, container);
mEditText = (EditText) view.findViewById(R.id.txt_your_name);
getDialog().setTitle("Hello");
return view;
}
}
The dialog extends DialogFragment and includes the required empty constructor. Fragments implement the onCreateView()
method to actually load the view using the provided LayoutInflater.Showing the Dialog
Now we need some code in our Activity to show the dialog. Here is a simple example that immediately shows the EditNameDialog to enter the user’s name. On completion, it shows a Toast with the entered text.import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
// ...
public class FragmentDialogDemo extends FragmentActivity implements EditNameDialogListener {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
showEditDialog();
}
private void showEditDialog() {
FragmentManager fm = getSupportFragmentManager();
EditNameDialog editNameDialog = new EditNameDialog();
editNameDialog.show(fm, "fragment_edit_name");
}
@Override
public void onFinishEditDialog(String inputText) {
Toast.makeText(this, "Hi, " + inputText, Toast.LENGTH_SHORT).show();
}
}
There
are a few things to notice here. First, because we’re using the support
library for backward compatibility with the Fragment API, our Activity
extends FragmentActivity from the support library. Because we’re using
the support library, we call getSupportFragmentManager()
instead of getFragmentManager()
.After loading the initial view, the activity immediately shows the EditNameDialog by calling its show() method. This allows the DialogFragment to ensure that what is happening with the Dialog and Fragment states remains consistent. By default, the back button will dismiss the dialog without any additional code.
Using the Dialog
Next, let’s enhance EditNameDialog so it can return a result string to the Activity.import android.support.v4.app.DialogFragment;
// ...
public class EditNameDialog extends DialogFragment implements OnEditorActionListener {
public interface EditNameDialogListener {
void onFinishEditDialog(String inputText);
}
private EditText mEditText;
public EditNameDialog() {
// Empty constructor required for DialogFragment
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_edit_name, container);
mEditText = (EditText) view.findViewById(R.id.txt_your_name);
getDialog().setTitle("Hello");
// Show soft keyboard automatically
mEditText.requestFocus();
getDialog().getWindow().setSoftInputMode(
LayoutParams.SOFT_INPUT_STATE_VISIBLE);
mEditText.setOnEditorActionListener(this);
return view;
}
@Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
if (EditorInfo.IME_ACTION_DONE == actionId) {
// Return input text to activity
EditNameDialogListener activity = (EditNameDialogListener) getActivity();
activity.onFinishEditDialog(mEditText.getText().toString());
this.dismiss();
return true;
}
return false;
}
}
For user convenience, we programmatically focus on the EditText with mEditText.requestFocus()
. Alternatively, we could have used the <requestFocus/>
tag in the layout XML to do this; however, in some cases it’s
preferable to request focus programmatically. For example, an
OnFocusChangeListener added in the Fragment’s onCreateView()
method won’t get called if you request focus in the layout XML.If the user focuses on an EditText, the soft keyboard will automatically appear. In order to force this to happen with our programmatic focus, we call
getDialog().getWindow().setSoftInputMode()
. Note that
many Window operations you might have done previously in a Dialog can
still be done in a DialogFragment, but you have to call getDialog().getWindow()
instead of just getWindow()
. The resulting dialog is shown on both a handset and tablet (not to scale):The
onEditorAction()
method handles the callback when the user presses the Done key. It gets
invoked because we’ve set an OnEditorActionListener on the EditText. It
calls back to the Activity to send the entered text. To do this,
EditNameDialog declares an interface EditNameDialogListener that is
implemented by the Activity. This enables the dialog to be reused by
many Activities. To invoke the callback method onFinishEditDialog()
,
it obtains a reference to the Activity which launched the dialog by
calling getActivity(), which all Fragments provide, and then casts it to
the interface type. In MVC architecture, this is a common pattern for allowing a view to communicate with a controller.We can dismiss the dialog one of two ways. Here we are calling dismiss() within the Dialog class itself. It could also be called from the Activity like the show() method.
Hopefully this sheds some more light on Fragments as they relate to Dialogs. You can find the sample code in this blog post on Google Code.
References for learning more about Fragments:
Android C2DM — Client Login key expiration
[This post is by Francesco Nerieri, engineering team lead for C2DM — Tim Bray]
In the upcoming weeks, some of the older Client Login authentication keys will expire. If you generated the token you’re currently using to authenticate with the C2DM servers before October 2011, it will stop working.
If the response from the C2DM servers contains an
Update-Client-Auth
header, you’ll need to replace the current token with the one included in the header. // Check for updated token header
String updatedAuthToken = conn.getHeaderField(UPDATE_CLIENT_AUTH);
if (updatedAuthToken != null && !authToken.equals(updatedAuthToken)) {
log.info("Got updated auth token from datamessaging servers: " +
updatedAuthToken);
serverConfig.updateToken(updatedAuthToken);
}
We
suggest that you start using the Update-Client-Auth response header to
update tokens regularly, as keys will expire periodically from now on.
For example, have a look at the Chrome to Phone service hosted on
code.google.com; this code takes care of authenticating via Client Login and then sending a message:Alternatively, you can manually generate a new Client Login token now and replace the one currently in use. ClientLogin can be used with any application that can make an HTTPS POST request. The POST request should be structured as a form post with the default encoding application/x-www-form-urlencoded, like this:
POST /accounts/ClientLogin HTTP/1.0 Content-type: application/x-www-form-urlencoded accountType=GOOGLE&Email=johndoe@gmail.com&Passwd=north23AZ&service=ac2dmIf the POST succeeds, the response contains the authorization token, labeled "Auth", which is your new token. You could even do this from the command line:
curl -d \ "accountType=HOSTED_OR_GOOGLE&Email=johndoe@gmail.com&Passwd=north23AZ&service=ac2dm" \ https://www.google.com/accounts/ClientLogin | \ grep AuthIf your request fails or if you are prompted for captchas, please read ClientLogin for Installed Applications. And of course, if you updated your code to use the Update-Client-Auth header after the keys had expired, then you will first need to manually generate a new token.
Have fun with C2DM!
New Seller Countries in Google Play
Over the past year we’ve been working to expand the list of countries and currencies from which Android developers can sell their products. Starting today, developers in Czech Republic, Israel, Poland, and Mexico can sell priced applications and in-app products on Google Play, using their local bank accounts for payments. Welcome developers!
If you develop Android apps in one of the new countries and want to get started selling them, visit play.google.com/apps/publish and set up a new Google Play developer account. Once you’ve uploaded your apps, you can price them in any available buyer currencies, publish, and then receive payouts and financial data in your local currency.
If you are based in Israel or Mexico and are currently selling apps through an AdSense merchant account, you will need to migrate your apps to a new Google Play developer account in your local currency. Watch for an email that provides complete information on the migration process and timeline.
Additionally, we encourage developers everywhere to visit the Developer Console as soon as possible to set prices for their products in the currencies of these new countries. Stay tuned for more announcements soon as we continue to roll out our new billing infrastructure to buyers and sellers throughout the world.
Join the discussion on
+Android Developers
+Android Developers
Accessibility: Are You Serving All Your Users?
[This post is by Joe Fernandez, a technical writer for developer.android.com who cares about accessibility and usability. — Tim Bray.]
We recently published some new resources to help developers make their Android applications more accessible:
“But,” you may be thinking, “What is accessibility, exactly? Why should I make it a priority? How do I do it? And most importantly, how do I spell it?” All good questions. Let’s hit some of the key points.
Accessibility is about making sure that Android users who have limited vision or other physical impairments can use your application just as well as all those folks in line at the supermarket checking email on their phones. It’s also about the Mom over in the produce section whose kids are driving her to distraction, and really needs to see that critical notification your application is trying to deliver. It’s also about you, in the future; Is your eyesight getting better over time? How about that hand-eye coordination?
When it comes down to it, making an application accessible is about having a deep commitment to usability, getting the details right and delighting your users. It also means stepping into new territory and getting a different perspective on your application. Try it out: Open up an application you developed (or your all-time favorite app), then close your eyes and try to complete a task. No peeking! A little challenging, right?
How Android Enables Accessibility
One of main ways that Android enables accessibility is by allowing users to hear spoken feedback that announces the content of user interface components as they interact with applications. This spoken feedback is provided by an accessibility service called TalkBack, which is available for free on Google Play and has become a standard component of recent Android releases.Now enable TalkBack, and try that eyes-closed experiment again. Being able to hear your application’s interface probably makes this experiment a little easier, but it’s still challenging. This type of interaction is how many folks with limited vision use their Android devices every day. The spoken feedback works because all the user interface components provided by the Android framework are built so they can provide descriptions of themselves to accessibility services like TalkBack.
Another key element of accessibility on Android devices is the ability to use alternative navigation. Many users prefer directional controllers such as D-pads, trackballs or keyboard arrows because it allows them to make discrete, predictable movements through a user interface. You can try out directional control with your apps using the virtual keyboard in the Android emulator or by installing and enabling the Eyes-Free Keyboard on your device. Android enables this type of navigation by default, but you, as a developer, may need to take a few steps to make sure users can effectively navigate your app this way.
How to Make Your Application Accessible
It would be great to be able to give you a standard recipe for accessibility, but the truth of the matter is that the right answer depends on the design and functionality of your application. Here are some key steps for ensuring that your application is accessible:- Task flows: Design well-defined, clear task flows with minimal navigation steps, especially for major user tasks, and make sure those tasks are navigable via focus controls (see item 4).
- Action target size: Make sure buttons and selectable areas are of sufficient size for users to easily touch them, especially for critical actions. How big? We recommend that touch targets be 48dp (roughly 9mm) or larger.
- Label user interface controls: Label user interface components that do not have visible text, especially ImageButton, ImageView, and EditText components. Use the android:contentDescription XML layout attribute or setContentDescription() to provide this information for accessibility services.
- Enable focus-based navigation: Make sure users can navigate your screen layouts using hardware-based or software directional controls (D-pads, trackballs and keyboards). In a few cases, you may need to make UI components focusable or change the focus order to be more logical.
- Use framework-provided controls: Use Android's built-in user interface controls whenever possible, as these components provide accessibility support by default.
- Custom view controls: If you build custom interface controls for your application, implement accessibility interfaces for your custom views and provide text labels for the controls.
- Test: Checking off the items on this list doesn’t guarantee your app is accessible. Test accessibility by attempting to navigate your application using directional controls, and also try eyes free navigation with the TalkBack service enabled.
<ImageButton
android:id="@+id/add_note_button"
android:src="@drawable/add_note_image"
android:contentDescription="@string/add_note_description"/>
Notice
that we’ve added a content description that accessibility services can
use to provide an audible explanation of the button. Users can navigate
to this button and activate it with directional controls, because
ImageButton objects are focusable by default (so you don’t have to
include the android:focusable="true"
attribute).The good news is that, in most cases, implementing accessibility isn’t about radically restructuring your application, but rather working through the subtle details of accessibility. Making sure your application is accessible is an opportunity to look at your app from a different perspective, improve the overall quality of your app and ensure that all your users have a great experience.
No comments:
Post a Comment