Bare bone login using Chrome custom tab.

This commit is contained in:
Docile-Alligator
2024-05-23 16:12:44 -04:00
parent 5d050204e7
commit 18aec38d9f
8 changed files with 318 additions and 43 deletions

View File

@ -63,6 +63,7 @@ dependencies {
implementation 'androidx.cardview:cardview:1.0.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
implementation 'androidx.activity:activity:1.8.0'
def lifecycleVersion = "2.7.0"
implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycleVersion"
implementation "androidx.lifecycle:lifecycle-livedata:$lifecycleVersion"

View File

@ -34,23 +34,42 @@
android:theme="@style/AppTheme"
android:usesCleartextTraffic="true"
tools:replace="android:label">
<activity
android:name=".activities.LoginChromeCustomTabActivity"
android:parentActivityName=".activities.MainActivity"
android:theme="@style/AppTheme.Slidable"
android:launchMode="singleTop"
android:exported="true">
<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="localhost"
android:scheme="infinity" />
</intent-filter>
</activity>
<activity
android:name=".activities.CommentFilterUsageListingActivity"
android:exported="false"
android:parentActivityName=".activities.SettingsActivity"
android:theme="@style/AppTheme.NoActionBar"
android:exported="false" />
android:theme="@style/AppTheme.NoActionBar" />
<activity
android:name=".activities.CustomizeCommentFilterActivity"
android:exported="false"
android:label="@string/customize_comment_filter_activity_label"
android:parentActivityName=".activities.SettingsActivity"
android:theme="@style/AppTheme.NoActionBar"
android:exported="false" />
android:theme="@style/AppTheme.NoActionBar" />
<activity
android:name=".activities.CommentFilterPreferenceActivity"
android:exported="false"
android:label="@string/comment_filter_preference_activity_label"
android:parentActivityName=".activities.SettingsActivity"
android:theme="@style/AppTheme.NoActionBar"
android:exported="false" />
android:theme="@style/AppTheme.NoActionBar" />
<activity
android:name=".activities.HistoryActivity"
android:exported="false"
@ -122,11 +141,6 @@
android:name=".activities.FetchRandomSubredditOrPostActivity"
android:parentActivityName=".activities.MainActivity"
android:theme="@style/AppTheme.NoActionBar" />
<activity
android:name=".activities.GiveAwardActivity"
android:label="@string/give_award_activity_label"
android:parentActivityName=".activities.MainActivity"
android:theme="@style/AppTheme.Slidable" />
<activity
android:name=".activities.SelectUserFlairActivity"
android:parentActivityName=".activities.MainActivity"

View File

@ -29,6 +29,7 @@ import ml.docilealligator.infinityforreddit.activities.InboxActivity;
import ml.docilealligator.infinityforreddit.activities.LinkResolverActivity;
import ml.docilealligator.infinityforreddit.activities.LockScreenActivity;
import ml.docilealligator.infinityforreddit.activities.LoginActivity;
import ml.docilealligator.infinityforreddit.activities.LoginChromeCustomTabActivity;
import ml.docilealligator.infinityforreddit.activities.MainActivity;
import ml.docilealligator.infinityforreddit.activities.MultiredditSelectionActivity;
import ml.docilealligator.infinityforreddit.activities.PostFilterPreferenceActivity;
@ -313,6 +314,8 @@ public interface AppComponent {
void inject(CustomThemeListingFragment customThemeListingFragment);
void inject(LoginChromeCustomTabActivity loginChromeCustomTabActivity);
@Component.Factory
interface Factory {
AppComponent create(@BindsInstance Application application);

View File

@ -1,6 +1,5 @@
package ml.docilealligator.infinityforreddit.activities;
import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Bitmap;
@ -21,10 +20,10 @@ import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.core.app.ActivityCompat;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import org.greenrobot.eventbus.EventBus;
import org.json.JSONException;
import org.json.JSONObject;
@ -45,6 +44,7 @@ import ml.docilealligator.infinityforreddit.asynctasks.ParseAndInsertNewAccount;
import ml.docilealligator.infinityforreddit.customtheme.CustomThemeWrapper;
import ml.docilealligator.infinityforreddit.customviews.slidr.Slidr;
import ml.docilealligator.infinityforreddit.databinding.ActivityLoginBinding;
import ml.docilealligator.infinityforreddit.events.NewUserLoggedInEvent;
import ml.docilealligator.infinityforreddit.utils.APIUtils;
import ml.docilealligator.infinityforreddit.utils.SharedPreferencesUtils;
import ml.docilealligator.infinityforreddit.utils.Utils;
@ -114,18 +114,6 @@ public class LoginActivity extends BaseActivity {
isAgreeToUserAgreement = savedInstanceState.getBoolean(IS_AGREE_TO_USER_AGGREMENT_STATE);
}
binding.fabLoginActivity.setOnClickListener(view -> {
new MaterialAlertDialogBuilder(this, R.style.MaterialAlertDialogTheme)
.setTitle(R.string.have_trouble_login_title)
.setMessage(R.string.have_trouble_login_message)
.setPositiveButton(R.string.yes, (dialogInterface, i) -> {
enableDom = !enableDom;
ActivityCompat.recreate(this);
})
.setNegativeButton(R.string.no, null)
.show();
});
if (enableDom) {
binding.twoFaInfOTextViewLoginActivity.setVisibility(View.GONE);
}
@ -144,6 +132,22 @@ public class LoginActivity extends BaseActivity {
String url = uriBuilder.toString();
binding.fabLoginActivity.setOnClickListener(view -> {
/*new MaterialAlertDialogBuilder(this, R.style.MaterialAlertDialogTheme)
.setTitle(R.string.have_trouble_login_title)
.setMessage(R.string.have_trouble_login_message)
.setPositiveButton(R.string.yes, (dialogInterface, i) -> {
enableDom = !enableDom;
ActivityCompat.recreate(this);
})
.setNegativeButton(R.string.no, null)
.show();*/
Intent intent = new Intent(this, LoginChromeCustomTabActivity.class);
startActivity(intent);
finish();
});
CookieManager.getInstance().removeAllCookies(aBoolean -> {
});
@ -190,8 +194,7 @@ public class LoginActivity extends BaseActivity {
ParseAndInsertNewAccount.parseAndInsertNewAccount(mExecutor, new Handler(), name, accessToken, refreshToken, profileImageUrl, bannerImageUrl,
karma, authCode, mRedditDataRoomDatabase.accountDao(),
() -> {
Intent resultIntent = new Intent();
setResult(Activity.RESULT_OK, resultIntent);
EventBus.getDefault().post(new NewUserLoggedInEvent());
finish();
});
}

View File

@ -0,0 +1,247 @@
package ml.docilealligator.infinityforreddit.activities;
import android.content.ActivityNotFoundException;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.widget.Toast;
import androidx.activity.EdgeToEdge;
import androidx.annotation.NonNull;
import androidx.browser.customtabs.CustomTabColorSchemeParams;
import androidx.browser.customtabs.CustomTabsIntent;
import androidx.browser.customtabs.CustomTabsService;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
import org.greenrobot.eventbus.EventBus;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executor;
import javax.inject.Inject;
import javax.inject.Named;
import ml.docilealligator.infinityforreddit.FetchMyInfo;
import ml.docilealligator.infinityforreddit.Infinity;
import ml.docilealligator.infinityforreddit.R;
import ml.docilealligator.infinityforreddit.RedditDataRoomDatabase;
import ml.docilealligator.infinityforreddit.apis.RedditAPI;
import ml.docilealligator.infinityforreddit.asynctasks.ParseAndInsertNewAccount;
import ml.docilealligator.infinityforreddit.customtheme.CustomThemeWrapper;
import ml.docilealligator.infinityforreddit.events.NewUserLoggedInEvent;
import ml.docilealligator.infinityforreddit.utils.APIUtils;
import ml.docilealligator.infinityforreddit.utils.SharedPreferencesUtils;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;
public class LoginChromeCustomTabActivity extends BaseActivity {
@Inject
@Named("no_oauth")
Retrofit mRetrofit;
@Inject
@Named("oauth")
Retrofit mOauthRetrofit;
@Inject
RedditDataRoomDatabase mRedditDataRoomDatabase;
@Inject
@Named("default")
SharedPreferences mSharedPreferences;
@Inject
@Named("current_account")
SharedPreferences mCurrentAccountSharedPreferences;
@Inject
CustomThemeWrapper mCustomThemeWrapper;
@Inject
Executor mExecutor;
@Override
protected void onCreate(Bundle savedInstanceState) {
((Infinity) getApplication()).getAppComponent().inject(this);
super.onCreate(savedInstanceState);
EdgeToEdge.enable(this);
setContentView(R.layout.activity_login_chrome_custom_tab);
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {
Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
return insets;
});
applyCustomTheme();
ArrayList<ResolveInfo> resolveInfos = getCustomTabsPackages(getPackageManager());
if (!resolveInfos.isEmpty()) {
CustomTabsIntent.Builder builder = new CustomTabsIntent.Builder();
// add share action to menu list
builder.setShareState(CustomTabsIntent.SHARE_STATE_ON);
builder.setDefaultColorSchemeParams(
new CustomTabColorSchemeParams.Builder()
.setToolbarColor(mCustomThemeWrapper.getColorPrimary())
.build());
CustomTabsIntent customTabsIntent = builder.build();
customTabsIntent.intent.setPackage(resolveInfos.get(0).activityInfo.packageName);
customTabsIntent.intent.putExtra("com.google.android.apps.chrome.EXTRA_OPEN_NEW_INCOGNITO_TAB", true);
try {
Uri.Builder uriBuilder = Uri.parse(APIUtils.OAUTH_URL).buildUpon();
uriBuilder.appendQueryParameter(APIUtils.CLIENT_ID_KEY, APIUtils.CLIENT_ID);
uriBuilder.appendQueryParameter(APIUtils.RESPONSE_TYPE_KEY, APIUtils.RESPONSE_TYPE);
uriBuilder.appendQueryParameter(APIUtils.STATE_KEY, APIUtils.STATE);
uriBuilder.appendQueryParameter(APIUtils.REDIRECT_URI_KEY, APIUtils.REDIRECT_URI);
uriBuilder.appendQueryParameter(APIUtils.DURATION_KEY, APIUtils.DURATION);
uriBuilder.appendQueryParameter(APIUtils.SCOPE_KEY, APIUtils.SCOPE);
customTabsIntent.launchUrl(this, uriBuilder.build());
} catch (ActivityNotFoundException e) {
// TODO catch this
}
}
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
Uri uri = intent.getData();
if (uri == null) {
return;
}
String authCode = uri.getQueryParameter("code");
if (authCode != null) {
String state = uri.getQueryParameter("state");
if (APIUtils.STATE.equals(state)) {
Map<String, String> params = new HashMap<>();
params.put(APIUtils.GRANT_TYPE_KEY, "authorization_code");
params.put("code", authCode);
params.put(APIUtils.REDIRECT_URI_KEY, APIUtils.REDIRECT_URI);
RedditAPI api = mRetrofit.create(RedditAPI.class);
Call<String> accessTokenCall = api.getAccessToken(APIUtils.getHttpBasicAuthHeader(), params);
accessTokenCall.enqueue(new Callback<>() {
@Override
public void onResponse(@NonNull Call<String> call, @NonNull Response<String> response) {
if (response.isSuccessful()) {
try {
String accountResponse = response.body();
if (accountResponse == null) {
//Handle error
return;
}
JSONObject responseJSON = new JSONObject(accountResponse);
String accessToken = responseJSON.getString(APIUtils.ACCESS_TOKEN_KEY);
String refreshToken = responseJSON.getString(APIUtils.REFRESH_TOKEN_KEY);
FetchMyInfo.fetchAccountInfo(mOauthRetrofit, mRedditDataRoomDatabase,
accessToken, new FetchMyInfo.FetchMyInfoListener() {
@Override
public void onFetchMyInfoSuccess(String name, String profileImageUrl, String bannerImageUrl, int karma) {
mCurrentAccountSharedPreferences.edit().putString(SharedPreferencesUtils.ACCESS_TOKEN, accessToken)
.putString(SharedPreferencesUtils.ACCOUNT_NAME, name)
.putString(SharedPreferencesUtils.ACCOUNT_IMAGE_URL, profileImageUrl).apply();
mCurrentAccountSharedPreferences.edit().remove(SharedPreferencesUtils.SUBSCRIBED_THINGS_SYNC_TIME).apply();
ParseAndInsertNewAccount.parseAndInsertNewAccount(mExecutor, new Handler(), name, accessToken, refreshToken, profileImageUrl, bannerImageUrl,
karma, authCode, mRedditDataRoomDatabase.accountDao(),
() -> {
EventBus.getDefault().post(new NewUserLoggedInEvent());
finish();
});
}
@Override
public void onFetchMyInfoFailed(boolean parseFailed) {
if (parseFailed) {
Toast.makeText(LoginChromeCustomTabActivity.this, R.string.parse_user_info_error, Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(LoginChromeCustomTabActivity.this, R.string.cannot_fetch_user_info, Toast.LENGTH_SHORT).show();
}
finish();
}
});
} catch (JSONException e) {
e.printStackTrace();
Toast.makeText(LoginChromeCustomTabActivity.this, R.string.parse_json_response_error, Toast.LENGTH_SHORT).show();
finish();
}
} else {
Toast.makeText(LoginChromeCustomTabActivity.this, R.string.retrieve_token_error, Toast.LENGTH_SHORT).show();
finish();
}
}
@Override
public void onFailure(@NonNull Call<String> call, @NonNull Throwable t) {
Toast.makeText(LoginChromeCustomTabActivity.this, R.string.retrieve_token_error, Toast.LENGTH_SHORT).show();
t.printStackTrace();
finish();
}
});
} else {
Toast.makeText(this, R.string.something_went_wrong, Toast.LENGTH_SHORT).show();
finish();
}
} else if ("access_denied".equals(uri.getQueryParameter("error"))) {
Toast.makeText(this, R.string.access_denied, Toast.LENGTH_SHORT).show();
finish();
}
}
@Override
public SharedPreferences getDefaultSharedPreferences() {
return mSharedPreferences;
}
@Override
public SharedPreferences getCurrentAccountSharedPreferences() {
return mCurrentAccountSharedPreferences;
}
@Override
public CustomThemeWrapper getCustomThemeWrapper() {
return mCustomThemeWrapper;
}
@Override
protected void applyCustomTheme() {
}
private ArrayList<ResolveInfo> getCustomTabsPackages(PackageManager pm) {
// Get default VIEW intent handler.
Intent activityIntent = new Intent()
.setAction(Intent.ACTION_VIEW)
.addCategory(Intent.CATEGORY_BROWSABLE)
.setData(Uri.fromParts("http", "", null));
// Get all apps that can handle VIEW intents.
List<ResolveInfo> resolvedActivityList = pm.queryIntentActivities(activityIntent, 0);
ArrayList<ResolveInfo> packagesSupportingCustomTabs = new ArrayList<>();
for (ResolveInfo info : resolvedActivityList) {
Intent serviceIntent = new Intent();
serviceIntent.setAction(CustomTabsService.ACTION_CUSTOM_TABS_CONNECTION);
serviceIntent.setPackage(info.activityInfo.packageName);
// Check if this package also resolves the Custom Tabs service.
if (pm.resolveService(serviceIntent, 0) != null) {
packagesSupportingCustomTabs.add(info);
}
}
return packagesSupportingCustomTabs;
}
}

View File

@ -4,7 +4,6 @@ import static androidx.appcompat.app.AppCompatDelegate.MODE_NIGHT_NO;
import static androidx.appcompat.app.AppCompatDelegate.MODE_NIGHT_YES;
import android.Manifest;
import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
@ -101,6 +100,7 @@ import ml.docilealligator.infinityforreddit.events.ChangeLockBottomAppBarEvent;
import ml.docilealligator.infinityforreddit.events.ChangeNSFWEvent;
import ml.docilealligator.infinityforreddit.events.ChangeRequireAuthToAccountSectionEvent;
import ml.docilealligator.infinityforreddit.events.ChangeShowAvatarOnTheRightInTheNavigationDrawerEvent;
import ml.docilealligator.infinityforreddit.events.NewUserLoggedInEvent;
import ml.docilealligator.infinityforreddit.events.RecreateActivityEvent;
import ml.docilealligator.infinityforreddit.events.SwitchAccountEvent;
import ml.docilealligator.infinityforreddit.fragments.PostFragment;
@ -141,8 +141,6 @@ public class MainActivity extends BaseActivity implements SortTypeSelectionCallb
private static final String NEW_ACCOUNT_NAME_STATE = "NANS";
private static final String INBOX_COUNT_STATE = "ICS";
private static final int LOGIN_ACTIVITY_REQUEST_CODE = 0;
MultiRedditViewModel multiRedditViewModel;
SubscribedSubredditViewModel subscribedSubredditViewModel;
AccountViewModel accountViewModel;
@ -798,8 +796,7 @@ public class MainActivity extends BaseActivity implements SortTypeSelectionCallb
} else if (stringId == R.string.settings) {
intent = new Intent(MainActivity.this, SettingsActivity.class);
} else if (stringId == R.string.add_account) {
Intent addAccountIntent = new Intent(MainActivity.this, LoginActivity.class);
startActivityForResult(addAccountIntent, LOGIN_ACTIVITY_REQUEST_CODE);
intent = new Intent(MainActivity.this, LoginActivity.class);
} else if (stringId == R.string.anonymous_account) {
SwitchToAnonymousMode.switchToAnonymousMode(mRedditDataRoomDatabase, mCurrentAccountSharedPreferences,
mExecutor, new Handler(), false, () -> {
@ -1046,17 +1043,6 @@ public class MainActivity extends BaseActivity implements SortTypeSelectionCallb
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == LOGIN_ACTIVITY_REQUEST_CODE && resultCode == Activity.RESULT_OK) {
Intent intent = new Intent(this, MainActivity.class);
startActivity(intent);
finish();
}
super.onActivityResult(requestCode, resultCode, data);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main_activity, menu);
@ -1290,6 +1276,13 @@ public class MainActivity extends BaseActivity implements SortTypeSelectionCallb
navigationWrapper.floatingActionButton.setVisibility(hideFab ? View.GONE : View.VISIBLE);
}
@Subscribe
public void onNewUserLoggedInEvent(NewUserLoggedInEvent event) {
Intent intent = new Intent(this, MainActivity.class);
startActivity(intent);
finish();
}
@Override
public void onLongPress() {
if (sectionsPagerAdapter != null) {

View File

@ -0,0 +1,4 @@
package ml.docilealligator.infinityforreddit.events;
public class NewUserLoggedInEvent {
}

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".activities.LoginChromeCustomTabActivity">
</androidx.constraintlayout.widget.ConstraintLayout>