I am new to android app development, but I have good knowledge of programming in JAVA and in general. I am trying to write an app for android which can enqueue music files to default music player in android (like Google Play Music). My app decides which song to play when, but I don't want to write a full-blown music player app. I just want to feed the existing player app with new music.
I am looking for something like "inter-app" communication (perhaps using Intent?) through which I can feed content to the music player and probably control the player itself.
I am not sure if such facility exist in android, so other alternative suggestions are also welcome. Also, please let me know if I didn't explain the problem properly.
Intents are a very powerful feature of Android to which there isn't any direct analog in Java. What you want to use is a mechanism known as an implicit Intent. Normally, when you launch one activity from another, you create an Intent and specify which activity to start. With an implicit Intent, you provide an action (Intent.ACTION_VIEW) and data (a URI pointing to a music file). Using an implicit Intent, you have a piece of data handled without knowing in advance which Activity will do the handling.
When you pass your Intent to startActivity(), the OS will attempt to resolve the data in the best way possible, typically popping up a list of apps that can possibly handle your data. The user selects the appropriate app and that app handles the Intent, playing your music file. Any app that registers as a service capable of potentially handling your data will show up in the list. After passing the Intent, your activity will go into the background, and the app handling the intent will come to the foreground.
Once the user has selected an app to handle the Intent from your Activity, that app will always be used to handle that kind of Intent by your Activity until you delete your own app's data.
Take a look at the official doc to get yourself started and then ask a new question when you have a more specific problem you're trying to address.
Here's a code sample that demonstrates a very simple implicit Intent example, by which a URL is opened without knowing which browser will open it:
package com.marsatomic.intentimplicitdemo;
import android.os.Bundle;
import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.view.Menu;
import android.view.View;
import android.widget.Button;
public class MainActivity extends Activity
{
public final static Uri URI = Uri.parse("http://www.marsatomic.com");
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button buttonConnect = (Button)findViewById(R.id.button_connect);
buttonConnect.setOnClickListener(new View.OnClickListener()
{
public void onClick(View v)
{
Intent i = new Intent(Intent.ACTION_VIEW, URI);
startActivity(i);
}
});
}
#Override
public boolean onCreateOptionsMenu(Menu menu)
{
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
}
Related
I have a very simple activity, that redirects the user to the app's Play Store page, when the button is clicked:
public class MyActivity extends AppCompatActivity {
private static final String PLAY_STORE_URI =
"market://details?id=" + BuildConfig.APPLICATION_ID;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.my_activity);
findViewById(R.id.go_to_play_store).setOnClickListener(this::goToPlayStore);
}
public void goToPlayStore(View view) {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse(PLAY_STORE_URI));
startActivity(intent);
}
}
Is it possible to write a test to check that the PlayStore is launched when the button is clicked? Better, is it possible to verify it shows the expected page?
I know that by using ActivityMonitors transitions between Activities can be tested. I also know that I can verify the Intents being sent using Espresso Intents. But can I actually check that a user action launches another app?
I would click the button, then use:
intended(allOf(
hasAction(Intent.ACTION_VIEW),
hasData("https://play.google.com/store/apps/...your app...")
))
I would suggest a slightly different question - is it you app's job to verify that? You'd be testing not your own app but Android OS and Google's Play Store App.
The way I've been approaching it is by being explicit about the boundaries, and aware of the possible scenarios.
What I mean by that is, extract the Intent manipulation and invocation logic into a thin service (that's the being explicit about boundaries part) and test your Activity correctly interacts with it (by constructing the Intent appropriately).
The part about possible scenarios is being aware of what can happen. For example what does your app do (if anything) if the user doesn't have Play Store on their phone.
I need to create a simple app without activity that just open a webpage in the browser.
This is my code:
package com.example.johnny.myapplication3;
import android.app.Application;
import android.test.ApplicationTestCase;
import android.content.Intent;
import android.net.Uri;
/**
* Testing Fundamentals
*/
public class ApplicationTest extends ApplicationTestCase<Application> {
public ApplicationTest() {
super(Application.class);
Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.google.com"));
startActivity(browserIntent);
}
}
But I get this error: Error: cannot find symbol method startActivity(Intent)
Why ?
ApplicationTestCase does not have a method startActivity. If you're creating an app, not a test case, it does not make sense to use TestCase classes at all.
Without some more info on what you want to do it's hard to help more.
"a simple app without activity that just open a webpage in the browser"
How is your app supposed to be started? If it doesn't have any activity it will not have any launcher icon. Is it supposed to start by reacting to a broadcast intent or something like that? If so, you need a receiver to handle that intent and perform the actions you need to perform. You cannot just create an app with no entry point at all, how is the system supposed to know when and how to launch it?
Assuming you do want an icon in the launcher, then you do need to register an activity. That activity could in turn finish itself and launch the browser using startActivity, but the activity must be there to act as an entry point.
import android.app.Activity;
import android.app.Service;
import android.app.WallpaperManager;
import android.content.Intent;
import android.os.Bundle;
public class Preview extends Activity {
public Preview() {
// TODO Auto-generated constructor stub
}
#Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
Intent intent = new Intent();
intent.setAction(WallpaperManager.ACTION_CHANGE_LIVE_WALLPAPER);
String pkg = Service.class.getPackage().getName();
}
}
I am curious about the use of Service.class.getPackage().getName();. I see the package name is gotten. My question is on the use of Service.class. What is meant by that or what object is being accessed.
Usually, this is used to initialize classes in Java (the know pattern is Class.forName("some.Clazz") ). It forces a class to be loaded and its static fields to be initialized (eg. commonly for JDBC drivers).
Now you're under andoid (then dalvik), where did you get this pattern?
It's a roundabout to get a String containing "android.app". As a side effect, it also loads the Service class (which is completely useless since it's a framework class and doesn't have any static initializers). If you're looking for the application's package name (the one declared in the manifest), you really should do this.getPackageName() (since Activity is a Context)
A facility for the application to tell the system about something it wants to be doing in the background (even when the user is not
directly interacting with the application). This corresponds to calls
to Context.startService(), which ask the system to schedule work for
the service, to be run until the service or someone else explicitly
stop it.
A facility for an application to expose some of its functionality to other applications. This corresponds to calls to
Context.bindService(), which allows a long-standing connection to be
made to the service in order to interact with it
Source: Android Dev Docs
Source: What is a service
I am trying to pick a song using an Activity which will give meta-information about the songs. I want to do this instead of a simple file browser . I have the following code but it unfortunately also plays the song once clicked. I simply want the user to be able to select a song from their MediaStore and act upon it later without playing.
public class Main extends Activity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Intent intent = new Intent();
intent.setAction(android.content.Intent.ACTION_PICK);
intent.setData(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI);
startActivity(intent);
}
}
As far as I can tell, the 'picker' you're seeing is a 'preview' type of design (looking at it on my phone).
It's a bit like 'picking' a ringtone, for example...
You see a list and can select each one in turn to get a 'preview'. When you decide on the ringtone you want, you click OK and that returns the selection. Clicking Cancel simply leaves things as they were (existing ringtone selection is kept).
I can't see any way of overriding this behaviour of the picker and haven't found any alternative way (Intent parameters, for example) to achieve what you want to do.
In other words, as I understand it, you simply want the user to silently pick a piece of music and it to return to your Activity but the (preview) picker doesn't work that way.
You can find out what the user previewed/selected when they click OK in the picker however, if you use...
startActivityForResult(intent, 1234);
Note, 1234 is just an arbitrary code.
If you check the Intent returned to onActivityResult() it will have the content Uri of the piece of music the user selected before they pressed OK.
I'm trying to implement my own phone call handling UI.
What I want to do is, if a call comes in, the incoming telephone number and a picture are displayed, and, if I press a button, the incoming call will be accepted/answered.
The related code is:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
answerButton = (Button) findViewById(R.id.pickup);
answerButton.setOnClickListener(new OnClickListener() {
public void onClick(final View v) {
Intent intent = new Intent("android.intent.action.ANSWER");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
});
Sadly, the code does not work. At first, an exception is thrown if I press my answer button:
ActivityNotFoundException: No Activity found to handle Intent {
act=android.intent.action.ANSWER
Then I added an entry in the AndroidManifest.xml:
<uses-permission android:name="android.permission.CALL_PHONE" />
I run the app again, there is no exception anymore. However, I doubt the incoming call is not really accepted. Because if the press the Android's screen answer button (green button), the incoming call is accepted and a green in call icon is also displayed on the upper left corner of the emulator screen, while my app doesn't.
I also read the Phone app's source code in android source. There is method such as acceptCall() in the Phone class. But these codes seem difficult for me to use, because there are many imports declaration in the code, such as :
import com.android.internal.telephony.Call;
import com.android.internal.telephony.CallStateException;
import com.android.internal.telephony.CallerInfo;
import com.android.internal.telephony.CallerInfoAsyncQuery;
import com.android.internal.telephony.Connection;
import com.android.internal.telephony.MmiCode;
import com.android.internal.telephony.Phone;
And, if I add these imports in my code, there will be too many errors, such as :
The import com.android.internal.telephony cannot be resolved.
What is the right and simple way for my problem?
Add the category "android.intent.category.DEFAULT" (Intent.CATEGORY_DEFAULT)
The intent android.intent.action.ANSWER is somehow not working as expected. There is a workaround by emulating the bluetooth button to answer the incoming call. You can see an example from auto-answer project.
You need to create a broadcast receiver in which you will get the event when your phone is ringing and after that you can launch your desired activity.You can not replace the default incoming call screen until using CUSTOM ROM.
And do not forget to set the priority in broadcast receiver in manifest file.
Once you get the event you can use the object of ITelephony by using reflection.And that can provide you methods to answering or rejecting the call.
This is possible using the com.android.internal.telephony package, but you have to find someway for using this methods in eclipse and your app has to be compiled as a system app using the android source code.
Change your accept call method by this:
public static void acceptCall(Context context)
{
Intent buttonUp = new Intent(Intent.ACTION_MEDIA_BUTTON);
buttonUp.putExtra(Intent.EXTRA_KEY_EVENT,
new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_HEADSETHOOK));
context.sendOrderedBroadcast(buttonUp, "android.permission.CALL_PRIVILEGED");
}