onCreate() gets called instead of onActivityResult() - android

So I am authenticating the user via GitHub account using OAuth from browser. But after I fire the Intent from LoginActivity, the onResume() gets executed before the user opens the browser, thus returning the value of uri equals null.
Here is the LoginActivity:
public class LoginActivity extends AppCompatActivity {
Button loginButton;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
loginButton = findViewById(R.id.button);
final String url = "oauth url...";
Log.d("called","oncreate");
loginButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.d("called","onclick");
attemptLogin(url);
}
});
}
private void attemptLogin(String url){
Log.d("called","onattempt");
Intent intent = new Intent(this, BrowserActivity.class);
intent.putExtra("URL", url);
startActivityForResult(intent, 1);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
Uri uri = data.getData();
String code = uri.getQueryParameter("code");
Log.d("called",code);
}
}
BrowserActivity:
public class BrowserActivity extends AppCompatActivity {
public static String CALLBACK_URL = "callback url..";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_browser);
Intent intent = getIntent();
if(intent != null){
String url = intent.getStringExtra("URL");
Intent i = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
startActivity(i);
}
}
#Override
protected void onResume() {
super.onResume();
Uri uri = getIntent().getData();
if(uri != null && uri.toString().startsWith(CALLBACK_URL)) {
String code = uri.getQueryParameter("code");
Intent intent = new Intent();
intent.putExtra("code",code);
setResult(RESULT_OK, intent);
finish();
}
}
}
LoginActivity in AndroidManifest.xml:
<activity
android:name=".ui.activities.LoginActivity"
android:label="#string/app_name"
android:theme="#style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".ui.activities.BrowserActivity"
android:label="#string/app_name"
android:theme="#style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data
android:host="callback"
android:scheme="app"
/>
</intent-filter>
</activity>

First, you start the browser with
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
startActivityForResult(intent, 1);
this intent does not return any result. It only request the browser to show the url. So the browser does not returning any result.
However, after authentification, the browser trigger an intent and request for a new instance of LoginActivity. onCreate() is called of course
It is like LoginActivity(#1) -> Browser -> LoginActivity(#2)
you can call this portion of code inside onCreate() it will work:
Uri uri = getIntent().getData();
String code = uri.getQueryParameter("code");
Log.d("called",code);
But two different intents(launcher and action_view) can reach the same activity for two different purposes. You'd better create two different activities. First your usual LoginActivity and a second one (which inherit from the first) BrowserActivity wich redifine onCreate. So far, your Manifest will look like
<activity
android:name=".ui.activities.LoginActivity"
android:label="#string/app_name"
android:theme="#style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".ui.activities.BrowserActivity"
android:label="#string/app_name"
android:theme="#style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data
android:host="callback"
android:scheme="app"
/>
</intent-filter>
</activity>
The LoginActivity code should look like this:
public class LoginActivity extends AppCompatActivity {
Button loginButton;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
loginButton = findViewById(R.id.button);
final String url = "oauth url...";
Log.d("called","oncreate");
loginButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.d("called","onclick");
attemptLogin(url);
}
});
}
private void attemptLogin(String url){
Log.d("called","onattempt");
// open the browser with url
Intent i = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
startActivity(i);
}
// no onResult
}
And this is the BrowserActivityCode:
public class BrowserActivity extends LoginActivity {
// this will be triggered after authentification
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
processIntent();
}
protected void processIntent() {
Intent intentFromBrowser = getIntent();
if (intentFromBrowser != null) {
Uri uri = intentFromBrowser.getData();
if(uri != null && uri.toString().startsWith(CALLBACK_URL)) {
String code = uri.getQueryParameter("code");
Log.d("code value", code);
}
}
}
}

Related

Android activity doesn't start regardless of the method used to start it

I've defined an android activity and it just fails to start regardless of how I try to start it. It's supposed to be launched as the main activity, but the app just hangs if I declare it as the default activity like this:
<activity
android:name=".activity.StartupActivity"
android:screenOrientation="portrait"
android:theme="#style/NoActionAppTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:host="url"
android:pathPrefix="/prefix"
android:scheme="https" />
<data
android:host="url"
android:scheme="https" />
</intent-filter>
</activity>
I've tried putting a breakpoint at the first line of onCreate and Log lines in this activity, but this activity just doesn't start. I think the source code of the activity is irrelevent since it doesn't ever start. Please let me know if it's needed. I tried setting another activity as the default one and start StartupActivity from it like this:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (! AppRuntime.b) {
AppRuntime.b = true;
startActivity(new Intent(this, StartupActivity.class));
finish();
return;
}
// other stuff
}
But the result is similar to what I see when StartupActivity is the default activity. The breakpoints in this activity work as expected. The problem arises when the StartupActivity is started. What's causing this problem?
Note: StartupActivity extends AppCompatActivity and overrides only onCreate and onActivityResult.
Edit: here's the activity code:
public class StartupActivity extends AppCompatActivity {
SharedPreferences sp;
String deepLink = "";
final int SIGNUP_REQUEST_CODE = 0;
final int TUTORIAL_REQUEST_CODE = 1;
#Override
public void onCreate(#Nullable Bundle savedInstanceState, #Nullable PersistableBundle persistentState) {
super.onCreate(savedInstanceState);
addressInvitation();
sp = App.getSharedPreferences();
MobileAds.initialize(this, Utils.getAdmobID());
setContentView(R.layout.activity_splash_screen);
//load the ad
// mAdView = findViewById(R.id.adView);
// AdRequest adRequest = new AdRequest.Builder().build();
// mAdView.loadAd(adRequest);
Log.d("DEBUGGING", "calling bootstrap");
bootstrapApp();
}
private void bootstrapApp() {
if (! sp.contains("signed_in")) {
sp.edit().clear().apply();
Log.d("DEBUGGING", "starting signup activity");
startActivityForResult(new Intent(this, SignUp.class), SIGNUP_REQUEST_CODE);
} else if (! sp.contains("isFirstTime")) {
Log.d("DEBUGGING", "starting tutorial");
startActivityForResult(new Intent(this, TutorialsActivity.class), TUTORIAL_REQUEST_CODE);
} else {
Log.d("DEBUGGING", "going to splash screen");
startActivity(new Intent(this, SplashScreen.class));
finish();
}
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case SIGNUP_REQUEST_CODE:
Log.d("DEBUGGING", "signup returned");
if (resultCode == RESULT_OK) {
sp.edit()
.putBoolean("signed_in", true)
.apply();
} else {
finish();
}
break;
case TUTORIAL_REQUEST_CODE:
Log.d("DEBUGGING", "tutorial returned");
if (resultCode == RESULT_OK) {
sp.edit()
.putBoolean("isFirstTime", true)
.apply();
} else {
finish();
}
break;
}
bootstrapApp();
}
private void addressInvitation() {
FirebaseDynamicLinks.getInstance().getDynamicLink(getIntent())
.addOnSuccessListener(this, new OnSuccessListener<PendingDynamicLinkData>() {
#Override
public void onSuccess(PendingDynamicLinkData data) {
if (data == null) {
return;
}
// Get the deep link
deepLink = data.getLink().toString();
// Extract invite
FirebaseAppInvite invite = FirebaseAppInvite.getInvitation(data);
if (invite != null) {
String invitationId = invite.getInvitationId();
}
}
})
.addOnFailureListener(this, new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Log.e("HandleInvitaiton", "COULD NOT HANDLE");
}
});
}
}
I see the problem. You're using
public void onCreate(Bundle savedInstanceState, PersistableBundle persistentState)
instead of
protected void onCreate(#Nullable Bundle savedInstanceState)
You're overriding the wrong method.

Creating new activity gives error "Performing pause of activity that is not resumed"

I have created several activities via Intent's in the past, yet this error baffles me.
This is a simple tutorial given on Developer.Android's website for creating a new Activity
Problem:
The error is thrown before onPause() and after calling startActivityForResult() all in the same Activtiy
Error:
E/ActivityThread: Performing pause of activity that is not resumed: {wrap302.nmu.assignment_6_task_2_server/wrap302.nmu.assignment_6_task_2_server.MainActivity}
java.lang.RuntimeException: Performing pause of activity that is not resumed: {wrap302.nmu.assignment_6_task_2_server/wrap302.nmu.assignment_6_task_2_server.MainActivity}
at android.app.ActivityThread.performPauseActivity(ActivityThread.java:3398)
at android.app.ActivityThread.performPauseActivity(ActivityThread.java:3386)
at android.app.ActivityThread.handlePauseActivity(ActivityThread.java:3361)
at android.app.ActivityThread.-wrap13(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1374)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5471)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
Minimal Working Example:
public class MainActivity extends Activity {
public static String isHost = "isHost";
private Context mContext;
private Button btnHostGame;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mContext = this;
setContentView(R.layout.activity_main);
btnHostGame = (Button) findViewById(R.id.btnHostGame);
btnHostGame.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
startGameActivity(true);
}
});
}
private void startGameActivity(boolean isHosting) {
Intent intent = new Intent(mContext, GameConnector.class);
intent.putExtra(isHost, isHosting);
startActivityForResult(intent, 0); //Exception occurs after this method
}
#Override
protected void onResume() {
super.onResume();
getActionBar().hide();
}
// Exception occurs before this method is called
#Override
protected void onPause() {
super.onPause();
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
Toast.makeText(mContext, "Did you win?", Toast.LENGTH_SHORT).show();
}
}
This is quite strange to me, any advice?
UPDATE
AndroidManifest request
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="wrap302.nmu.assignment_6_task_2_server">
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.VIBRATE"/>
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme.NoActionBar">
<activity android:name=".MainActivity"
android:label="#string/title_game">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity
android:name=".GameConnector"
android:label="#string/title_gameconnector">
<intent-filter>
<action android:name="android.intent.action.SEND"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
<activity
android:name=".Game"
android:label="#string/title_game">
<intent-filter>
<action android:name="android.intent.action.SEND"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
</application>
</manifest>
yes, GameConnector does get created without a problem.
However, the Exception is thrown before the GameConnector.onCreate method is called.
UPDATE 2
GameConnector code request
public class GameConnector extends Activity implements FragmentFinishListener{
public static String GameType = "GameType", GameConnect = "GameConnect";
public static String PlayerName = "PlayerName";
private FragmentManager fragmentManager;
private Fragment gameTypeFragment;
private Intent gameIntent;
private boolean isHosting;
private Context mContext;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_gameconnector);
mContext = this;
gameIntent = getIntent();
if (gameIntent.hasExtra(MainActivity.isHost))
isHosting = gameIntent.getBooleanExtra(MainActivity.isHost, false);
fragmentManager = getFragmentManager();
gameTypeFragment = (isHosting)
? new FragmentHostGame().setOnFragmentFinishListener(this)
: new FragmentJoinGame().setOnFragmentFinishListener(this);
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.add(R.id.fragmentContainer, gameTypeFragment, GameType);
fragmentTransaction.commit();
}
#Override
public void finished(Bundle bundle) {
GameConnection gameConnection = null;
if (bundle != null){
if (bundle.containsKey(GameConnect))
gameConnection = (GameConnection) bundle.getSerializable(GameConnect);
}
fragmentManager.beginTransaction().remove(gameTypeFragment).commit();
startGame(isHosting, gameConnection);
}
private void startGame(boolean isHosting, GameConnection gameConnection) {
Intent intent = new Intent(mContext, Game.class);
intent.putExtra(MainActivity.isHost, isHosting);
intent.putExtra(GameConnect, gameConnection);
startActivityForResult(intent, 0);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (data != null){
switch (requestCode){
case 0:{
if (resultCode == 0){
finishActivity(resultCode);
}
else {
setResult(resultCode, data);
finishActivity(1);
}
break;
}
}
}
setResult(resultCode, null);
finishActivity(1);
}
}

How to get the proper actions from intent on android

There are two applications : Caller, Callee
Case 1 >
When I launch Callee application from home screen, I can get an action("android.intent.action.MAIN") from INTENT.
While Callee is running, I launch Callee application with an action("andoird.intent.action.test") again from Caller application. Then I get the action("android.intent.action.MAIN"). not action("andoird.intent.action.test").
How can I get the action("andoird.intent.action.test")?
Case 2 >
When I launch Callee application with an action("andoird.intent.action.test"), I get the action("andoird.intent.action.test").
While Callee is running, I launch Callee application from the home screen. Then I get the action("andoird.intent.action.test"). not action("android.intent.action.Main").
How can I get the action("android.intent.action.Main")?
What am I missing to get the proper action?
Here is Caller code below.
public class CallerActivity extends AppCompatActivity {
public static final String ACTION_TEST = "android.intent.action.test";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button test = (Button) findViewById(R.id.gotoSetting);
test.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = getPackageManager().getLaunchIntentForPackage(PACKAGE);
intent.setAction(ACTION_TEST);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP);
startActivity(intent);
}
});
}
}
Here is Callee code below.
public class CalleeActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.e("test", "onCreate()");
Log.e("test", getIntent().getAction());
}
#Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
Log.e("test", "onNewIntent()");
Log.e("test", getIntent().getAction());
}
}
Here is Callee's AndroidManifest.
<activity
android:name=".CalleeActivity"
android:launchMode="singleTop"
android:screenOrientation="portrait"
android:windowSoftInputMode="stateHidden">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.test"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
Please help.
Replace this code:
#Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
Log.e("test", "onNewIntent()");
Log.e("test", getIntent().getAction());// getIntent() will return old intent
}
with
#Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
Log.e("test", "onNewIntent()");
Log.e("test", intent.getAction()); //use new intent
}

Android Phone Call UI - Change

How do I change the phone call user interface? Like I have my own dialer layout and contacts layout but how do I change the calling UI. So, when the call is going on, can I remove the speaker button for example?
Here is my dialer scene that I have created: Dialer Picture
But I don't know how to edit this screen: Calling Picture
EDIT: I have already built the UI, I just can not get it to show during call!
Here is the code for as a simpler version:
public class MainActivity extends Activity {
private Button callBtn;
private Button dialBtn;
private EditText number;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
number = (EditText) findViewById(R.id.phoneNumber);
callBtn = (Button) findViewById(R.id.call);
dialBtn = (Button) findViewById(R.id.dial);
// add PhoneStateListener for monitoring
MyPhoneListener phoneListener = new MyPhoneListener();
TelephonyManager telephonyManager =
(TelephonyManager) this.getSystemService(Context.TELEPHONY_SERVICE);
// receive notifications of telephony state changes
telephonyManager.listen(phoneListener,PhoneStateListener.LISTEN_CALL_STATE);
callBtn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
try {
// set the data
String uri = "tel:"+number.getText().toString();
Intent callIntent = new Intent(Intent.ACTION_CALL, Uri.parse(uri));
startActivity(callIntent);
}catch(Exception e) {
Toast.makeText(getApplicationContext(),"Your call has failed...",
Toast.LENGTH_LONG).show();
e.printStackTrace();
}
}
});
dialBtn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
try {
String uri = "tel:"+number.getText().toString();
Intent dialIntent = new Intent(Intent.ACTION_DIAL, Uri.parse(uri));
startActivity(dialIntent);
}catch(Exception e) {
Toast.makeText(getApplicationContext(),"Your call has failed...",
Toast.LENGTH_LONG).show();
e.printStackTrace();
}
}
});
}
private class MyPhoneListener extends PhoneStateListener {
private boolean onCall = false;
#Override
public void onCallStateChanged(int state, String incomingNumber) {
switch (state) {
case TelephonyManager.CALL_STATE_RINGING:
// phone ringing...
Toast.makeText(MainActivity.this, incomingNumber + " calls you",
Toast.LENGTH_LONG).show();
break;
case TelephonyManager.CALL_STATE_OFFHOOK:
// one call exists that is dialing, active, or on hold
Toast.makeText(MainActivity.this, "on call...",
Toast.LENGTH_LONG).show();
//because user answers the incoming call
onCall = true;
break;
case TelephonyManager.CALL_STATE_IDLE:
// in initialization of the class and at the end of phone call
// detect flag from CALL_STATE_OFFHOOK
if (onCall == true) {
Toast.makeText(MainActivity.this, "restart app after call",
Toast.LENGTH_LONG).show();
// restart our application
Intent restart = getBaseContext().getPackageManager().
getLaunchIntentForPackage(getBaseContext().getPackageName());
restart.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(restart);
onCall = false;
}
break;
default:
break;
}
}
}
}
Thanks!
Add calling permission in manifest
<uses-permission android:name="android.permission.CALL_PHONE" />
Then need to check if call button pressed. for that use below intent filter
<intent-filter>
<action android:name="android.intent.action.CALL_BUTTON" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
and when firing the UI
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<action android:name="android.intent.action.DIAL" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="tel" />
</intent-filter>
that means your calling activity in manifest will be something like this
<activity
android:name="com.example.MainActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<!-- open activity when establishing a call -->
<intent-filter>
<action android:name="android.intent.action.CALL_PRIVILEGED" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="tel" />
</intent-filter>
</activity>
since API 23 it is possible, see Replacing default Phone app on Android 6 and 7 with InCallService arekolek.
Kotlin version: Simple Phone
Java version: Simple Phone Dialer
EDIT
As recommended, Below is the simplest java version.
Below is shown the Manifest with the intent-filter needed.
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.aliton.customphonecall">
<uses-permission android:name="android.permission.CALL_PHONE" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".DialerActivity" >
<intent-filter>
<!-- Handle links from other applications -->
<action android:name="android.intent.action.VIEW" />
<action android:name="android.intent.action.DIAL" />
<!-- Populate the system chooser -->
<category android:name="android.intent.category.DEFAULT" />
<!-- Handle links in browsers -->
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="tel" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.DIAL" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<service
android:name=".CallService"
android:permission="android.permission.BIND_INCALL_SERVICE">
<meta-data
android:name="android.telecom.IN_CALL_SERVICE_UI"
android:value="true" />
<intent-filter>
<action android:name="android.telecom.InCallService" />
</intent-filter>
</service>
<activity android:name=".CallActivity"></activity>
</application>
</manifest>
The MainActivity just have a Button with an Intent redirecting to the DialerActivity.
Below is the DialerActivity. In this Activity, you will set your app as default in order to make call with your UI.
public class DialerActivity extends AppCompatActivity {
private static final int REQUEST_CALL_PHONE = 10;
EditText phoneNumber;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_dialer);
phoneNumber = (EditText) findViewById(R.id.etNumber);
Button bCall = (Button) findViewById(R.id.btnCall);
offerReplacingDefaultDialer();
bCall.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
makeCall();
}
});
}
private void makeCall() {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CALL_PHONE) == PackageManager.PERMISSION_GRANTED) {
Uri uri = Uri.parse("tel:"+phoneNumber.getText().toString().trim());
Intent Call = new Intent(Intent.ACTION_CALL, uri);
//Toast.makeText(this, "Entered makeCall()", Toast.LENGTH_SHORT).show();
Log.i("debinf Dialer", "Entered makeCall()");
startActivity(Call);
} else {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CALL_PHONE}, REQUEST_CALL_PHONE);
}
}
private void offerReplacingDefaultDialer() {
if (getSystemService(TelecomManager.class).getDefaultDialerPackage() != getPackageName()) {
Intent ChangeDialer = new Intent(TelecomManager.ACTION_CHANGE_DEFAULT_DIALER);
ChangeDialer.putExtra(TelecomManager.EXTRA_CHANGE_DEFAULT_DIALER_PACKAGE_NAME, getPackageName());
startActivity(ChangeDialer);
}
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == REQUEST_CALL_PHONE) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
makeCall();
} else {
Toast.makeText(this, "calling permission denied", Toast.LENGTH_LONG).show();
}
//return;
}
}
}
Here is how InCallService is implemented to manage the calls.
public class CallService extends InCallService {
OngoingCallObject ongoingCallObject;
#Override
public void onCallAdded(Call call) {
super.onCallAdded(call);
new OngoingCallObject().setCall(call);
//Intent CallAct = new Intent(this, CallActivity.class);
//startActivity(CallAct);
CallActivity.start(this, call);
}
#Override
public void onCallRemoved(Call call) {
super.onCallRemoved(call);
new OngoingCallObject().setCall(null);
}
}
Here is how the Object is implemented.
public class OngoingCallObject {
private static Call call;
private Object callback = new Callback() {
#Override
public void onStateChanged(Call call, int state) {
super.onStateChanged(call, state);
Log.i("debinf OngoingObj", "state is "+state);
}
};
public void setCall(Call call) {
if (this.call != null) {
this.call.unregisterCallback((Call.Callback)callback);
}
if (call != null) {
call.registerCallback((Call.Callback)callback);
Log.i("debinf OngoingObj", "call.getState() is "+call.getState());
}
this.call = call;
}
public void answer() {
//assert this.call != null;
if (this.call != null) {
this.call.answer(VideoProfile.STATE_AUDIO_ONLY);
}
}
public void hangup() {
//assert this.call != null;
if (this.call != null) {
this.call.disconnect();
}
}
}
And finally, the CallActivity where you launch your UI.
public class CallActivity extends AppCompatActivity {
TextView callInfo;
Button answer, hangup;
private String number;
private OngoingCallObject ongoingCall;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_call);
ongoingCall = new OngoingCallObject();
answer = (Button) findViewById(R.id.answer);
hangup = (Button) findViewById(R.id.hangup);
callInfo = (TextView) findViewById(R.id.callInfo);
number = Objects.requireNonNull(getIntent().getData().getSchemeSpecificPart());
callInfo.setText("Calling number : "+number);
answer.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//Toast.makeText(CallActivity.this, "Answer button", Toast.LENGTH_SHORT).show();
ongoingCall.answer();
}
});
hangup.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
ongoingCall.hangup();
}
});
}
public static void start(Context context, Call call) {
Intent intent = new Intent(context, CallActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setData(call.getDetails().getHandle());
context.startActivity(intent);
}
}
Here is the xml for DialerActivity: activity_dialer.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".DialerActivity">
<EditText
android:id="#+id/etNumber"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Tel number"/>
<Button
android:id="#+id/btnCall"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="CallActivity"
android:layout_below="#+id/etNumber" />
</RelativeLayout>
Here is the xml for CallActivity: activity_call.xml
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".CallActivity">
<TextView
android:id="#+id/callInfo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.3"
tools:text="Hello World!" />
<Button
android:id="#+id/answer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Answer"
app:layout_constraintBaseline_toBaselineOf="#+id/hangup"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="#+id/hangup" />
<Button
android:id="#+id/hangup"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hang up"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="#+id/answer"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/callInfo" />
</android.support.constraint.ConstraintLayout>
I hope it helps!
EDIT:
Actually the api 23 was release, check this answer. Keep in mind that some devices may not support this functionality.
PREVIEW:
The actual calling view (what you see during calls) CAN`T be changed.
To be more specific, some parts of android CAN NOT be overridden,
android has his core and as developers we have limited access to this
core. In your case you can override dialer but you can`t
override actual phone call view.
You can't do anything about this, until android team decided to share
this core feature with us (developers).
Build your own Dialer UI. Check this out.
You will need an Activity to handle the intent and then displaying a custom UI is your business.

Android : Video Intent Opening Error : Source not found

I am trying to use the intent to select a video which I want to play using videoplayer. I am not able to get the intent working instead i am getting the Source Not Found error.
Thanks for your help.
This is my code :
Manifest
<application
android:label="#string/app_name"
android:icon="#drawable/ic_launcher">
<activity
android:name="SurfaceActivity"
android:label="#string/app_name"
android:configChanges="orientation|screenSize"
android:screenOrientation="landscape" >
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
Code:
public class SurfaceActivity extends Activity implements TextureView.SurfaceTextureListener, OnPreparedListener, MediaController.MediaPlayerControl
{
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
loadVideo = (Button) findViewById(R.id.Load);
// surface.setSurfaceTextureListener(this);
loadVideo.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View arg0) {
Intent intent = new Intent();
intent.setType("video/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(Intent.createChooser(intent, "Video File to Play"), 0);
}
});
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
if (requestCode == 0)
{
if (resultCode == RESULT_OK)
{
Uri sourceUri = data.getData();
String source = getPath(sourceUri);
//startPlayback(source);
startPlaying(source);
}
}
}
}

Categories

Resources