Finish ask permission dialog UI
BIN
res/drawable-hdpi/ic_generic_man.png
Normal file
After Width: | Height: | Size: 2.3 KiB |
BIN
res/drawable-mdpi/ic_generic_man.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
res/drawable-xhdpi/ic_generic_man.png
Normal file
After Width: | Height: | Size: 3.1 KiB |
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 3.0 KiB |
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 3.8 KiB |
BIN
res/drawable-xhdpi/proprietary_auth_ic_scope_icon_default.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
res/drawable-xxhdpi/ic_generic_man.png
Normal file
After Width: | Height: | Size: 3.5 KiB |
19
res/drawable/circle_shape_background.xml
Normal file
@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
~ Copyright 2013-2015 µg Project Team
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="oval">
|
||||
<solid android:color="@color/dialog_border_color" />
|
||||
</shape>
|
@ -15,46 +15,72 @@
|
||||
-->
|
||||
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<TextView
|
||||
android:gravity="center_horizontal"
|
||||
android:padding="10dp"
|
||||
android:text="@string/account_manager_title"
|
||||
android:textColor="?attr/colorPrimary"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<View
|
||||
android:background="@color/dialog_border_color"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp" />
|
||||
|
||||
<LinearLayout
|
||||
android:padding="50dp"
|
||||
android:paddingTop="15dp"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<de.hdodenhof.circleimageview.CircleImageView
|
||||
android:src="@color/login_blue_theme_accent"
|
||||
android:id="@+id/account_photo"
|
||||
android:layout_marginRight="-5dp"
|
||||
<FrameLayout
|
||||
android:background="@drawable/circle_shape_background"
|
||||
android:layout_marginEnd="-3dp"
|
||||
android:layout_marginRight="-3dp"
|
||||
android:layout_width="64dp"
|
||||
android:layout_height="64dp"
|
||||
app:border_width="10dp"
|
||||
app:border_color="#88888888" />
|
||||
android:padding="10dp">
|
||||
|
||||
<de.hdodenhof.circleimageview.CircleImageView
|
||||
android:src="@color/login_blue_theme_primary"
|
||||
android:id="@+id/app_icon"
|
||||
android:layout_marginLeft="-5dp"
|
||||
<de.hdodenhof.circleimageview.CircleImageView
|
||||
android:src="@drawable/ic_generic_man"
|
||||
android:id="@+id/account_photo"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
</FrameLayout>
|
||||
|
||||
<FrameLayout
|
||||
android:background="@drawable/circle_shape_background"
|
||||
android:layout_marginStart="-3dp"
|
||||
android:layout_marginLeft="-3dp"
|
||||
android:layout_width="64dp"
|
||||
android:layout_height="64dp"
|
||||
app:border_width="10dp"
|
||||
app:border_color="#88888888" />
|
||||
android:padding="10dp">
|
||||
|
||||
<ImageView
|
||||
android:src="@drawable/ic_microg_app"
|
||||
android:id="@+id/app_icon"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
</FrameLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/title"
|
||||
android:padding="10dp"
|
||||
android:padding="15dp"
|
||||
android:gravity="center_horizontal"
|
||||
android:textSize="18sp"
|
||||
android:text="%NAME% would like to:"
|
||||
android:textColor="?attr/colorAccent"
|
||||
android:text="@string/ask_permission_title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<ListView
|
||||
android:padding="5dp"
|
||||
android:id="@+id/permissions"
|
||||
android:layout_weight="1"
|
||||
android:layout_width="match_parent"
|
||||
@ -62,23 +88,33 @@
|
||||
|
||||
<TextView
|
||||
android:padding="10dp"
|
||||
android:text="By continuing, you will allow this app and Google to use your information in accordance with their respective terms of service and privacy services."
|
||||
android:textColor="?attr/colorPrimary"
|
||||
android:textSize="12sp"
|
||||
android:text="@string/ask_permission_tos"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_gravity="end"
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:paddingRight="10dp"
|
||||
android:paddingLeft="10dp"
|
||||
android:paddingBottom="5dp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<Button
|
||||
android:text="@android:string/cancel"
|
||||
android:layout_weight="1"
|
||||
android:layout_width="0dip"
|
||||
android:id="@android:id/button2"
|
||||
style="?android:attr/buttonBarButtonStyle"
|
||||
android:text="@string/deny"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<Button
|
||||
android:text="@android:string/ok"
|
||||
android:layout_weight="1"
|
||||
android:layout_width="0dip"
|
||||
android:id="@android:id/button1"
|
||||
style="?android:attr/buttonBarButtonStyle"
|
||||
android:text="@string/allow"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
</LinearLayout>
|
||||
|
||||
|
35
res/layout/ask_permission_list_entry.xml
Normal file
@ -0,0 +1,35 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
~ Copyright 2013-2015 µg Project Team
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="horizontal"
|
||||
android:padding="5dp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<ImageView
|
||||
android:src="@drawable/proprietary_auth_ic_scope_icon_default"
|
||||
android:id="@android:id/icon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<TextView
|
||||
android:padding="6dp"
|
||||
android:textSize="16sp"
|
||||
android:id="@android:id/text1"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
</LinearLayout>
|
@ -18,4 +18,6 @@
|
||||
<color name="login_blue_theme_primary">#ff4285f4</color>
|
||||
<color name="login_blue_theme_primary_dark">#ff3367d6</color>
|
||||
<color name="login_blue_theme_accent">#ffFFAB40</color>
|
||||
|
||||
<color name="dialog_border_color">#88CCCCCC</color>
|
||||
</resources>
|
||||
|
92
res/values/permissions.xml
Normal file
@ -0,0 +1,92 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright 2013-2015 µg Project Team
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<resources>
|
||||
<string name="permission_service_all_label">All Google services</string>
|
||||
<string name="permission_service_all_description">Allows app to access all Google services through any associated Google account.</string>
|
||||
|
||||
<string name="permission_service_android_label">Android services</string>
|
||||
<string name="permission_service_android_description">Allows app to access Android services through any associated Google account.</string>
|
||||
<string name="permission_service_adsense_label">AdSense</string>
|
||||
<string name="permission_service_adsense_description">Allows app to access AdSense through any associated Google account.</string>
|
||||
<string name="permission_service_adwords_label">AdWords</string>
|
||||
<string name="permission_service_adwords_description">Allows app to access AdWords through any associated Google account.</string>
|
||||
<string name="permission_service_ah_label">Google App Engine</string>
|
||||
<string name="permission_service_ah_description">Allows app to access Google App Engine through any associated Google account.</string>
|
||||
<string name="permission_service_blogger_label">Blogger</string>
|
||||
<string name="permission_service_blogger_description">Allows app to access Blogger through any associated Google account.</string>
|
||||
<string name="permission_service_cl_label">Google Calendar</string>
|
||||
<string name="permission_service_cl_description">Allows app to access Google Calendar through any associated Google account.</string>
|
||||
<string name="permission_service_cp_label">Contacts</string>
|
||||
<string name="permission_service_cp_description">Allows app to access Contacts through any associated Google account.</string>
|
||||
<string name="permission_service_dodgeball_label">Dodgeball</string>
|
||||
<string name="permission_service_dodgeball_description">Allows app to access Dodgeball through any associated Google account.</string>
|
||||
<string name="permission_service_finance_label">Google Finance</string>
|
||||
<string name="permission_service_finance_description">Allows app to access Google Finance through any associated Google account.</string>
|
||||
<string name="permission_service_gbase_label">Google Base</string>
|
||||
<string name="permission_service_gbase_description">Allows app to access Google Base through any associated Google account.</string>
|
||||
<string name="permission_service_grandcentral_label">Google Voice</string>
|
||||
<string name="permission_service_grandcentral_description">Allows app to access Google Voice through any associated Google account.</string>
|
||||
<string name="permission_service_groups2_label">Google Groups</string>
|
||||
<string name="permission_service_groups2_description">Allows app to access Google Groups through any associated Google account.</string>
|
||||
<string name="permission_service_health_label">Google Health</string>
|
||||
<string name="permission_service_health_description">Allows app to access Google Health through any associated Google account.</string>
|
||||
<string name="permission_service_ig_label">iGoogle</string>
|
||||
<string name="permission_service_ig_description">Allows app to access iGoogle through any associated Google account.</string>
|
||||
<string name="permission_service_jotspot_label">JotSpot</string>
|
||||
<string name="permission_service_jotspot_description">Allows app to access JotSpot through any associated Google account.</string>
|
||||
<string name="permission_service_knol_label">Knol</string>
|
||||
<string name="permission_service_knol_description">Allows app to access Knol through any associated Google account.</string>
|
||||
<string name="permission_service_lh2_label">Picasa Web Albums</string>
|
||||
<string name="permission_service_lh2_description">Allows app to access Picasa Web Albums through any associated Google account.</string>
|
||||
<string name="permission_service_local_label">Google Maps</string>
|
||||
<string name="permission_service_local_description">Allows app to access Google Maps through any associated Google account.</string>
|
||||
<string name="permission_service_mail_label">Google Mail</string>
|
||||
<string name="permission_service_mail_description">Allows app to access Google Mail through any associated Google account.</string>
|
||||
<string name="permission_service_news_label">Google News</string>
|
||||
<string name="permission_service_news_description">Allows app to access Google News through any associated Google account.</string>
|
||||
<string name="permission_service_notebook_label">Google Notebook</string>
|
||||
<string name="permission_service_notebook_description">Allows app to access Google Notebook through any associated Google account.</string>
|
||||
<string name="permission_service_orkut_label">Orkut</string>
|
||||
<string name="permission_service_orkut_description">Allows app to access Orkut through any associated Google account.</string>
|
||||
<string name="permission_service_print_label">Google Book Search</string>
|
||||
<string name="permission_service_print_description">Allows app to access Google Book Search through any associated Google account.</string>
|
||||
<string name="permission_service_sierra_label">Google Checkout accounts</string>
|
||||
<string name="permission_service_sierra_description">Allows app to access Google Checkout accounts through any associated Google account.</string>
|
||||
<string name="permission_service_sierraqa_label">Google Checkout QA accounts</string>
|
||||
<string name="permission_service_sierraqa_description">Allows app to access Google Checkout QA accounts through any associated Google account.</string>
|
||||
<string name="permission_service_sierrasandbox_label">Google Checkout Sandbox accounts</string>
|
||||
<string name="permission_service_sierrasandbox_description">Allows app to access Google Checkout Sandbox accounts through any associated Google account.</string>
|
||||
<string name="permission_service_sitemaps_label">Google Webmaster Tools</string>
|
||||
<string name="permission_service_sitemaps_description">Allows app to access Google Webmaster Tools through any associated Google account.</string>
|
||||
<string name="permission_service_speech_label">Voice Search</string>
|
||||
<string name="permission_service_speech_description">Allows app to access Voice Search through any associated Google account.</string>
|
||||
<string name="permission_service_speechpersonalization_label">Personalized Speech Recognition</string>
|
||||
<string name="permission_service_speechpersonalization_description">Allows app to access Personalized Speech Recognition through any associated Google account.</string>
|
||||
<string name="permission_service_talk_label">Google Talk</string>
|
||||
<string name="permission_service_talk_description">Allows app to access Google Talk through any associated Google account.</string>
|
||||
<string name="permission_service_wifi_label">Google Wi-Fi</string>
|
||||
<string name="permission_service_wifi_description">Allows app to access Google Wi-Fi through any associated Google account.</string>
|
||||
<string name="permission_service_wise_label">Google Spreadsheets</string>
|
||||
<string name="permission_service_wise_description">Allows app to access Google Spreadsheets through any associated Google account.</string>
|
||||
<string name="permission_service_writely_label">Google Docs</string>
|
||||
<string name="permission_service_writely_description">Allows app to access Google Docs through any associated Google account.</string>
|
||||
<string name="permission_service_youtube_label">YouTube</string>
|
||||
<string name="permission_service_youtube_description">Allows app to access YouTube through any associated Google account.</string>
|
||||
<string name="permission_service_YouTubeUser_label">YouTube usernames</string>
|
||||
<string name="permission_service_YouTubeUser_description">Allows app to access YouTube username(s) used with any associated Google account.</string>
|
||||
</resources>
|
@ -15,8 +15,13 @@
|
||||
-->
|
||||
|
||||
<resources>
|
||||
<string name="gms_app_name">μg Services</string>
|
||||
<string name="gms_app_name">µg Services</string>
|
||||
<string name="just_a_sec">Just a sec…</string>
|
||||
<string name="google_account_type">com.google</string>
|
||||
<string name="google_account_label">Google</string>
|
||||
<string name="ask_permission_tos">By continuing, you allow this app and Google to use your information in accordance with their respective terms of service and privacy policies.</string>
|
||||
<string name="ask_permission_title">%s would like to:</string>
|
||||
<string name="account_manager_title">µg Google Account Manager</string>
|
||||
<string name="allow">Allow</string>
|
||||
<string name="deny">Deny</string>
|
||||
</resources>
|
||||
|
@ -18,6 +18,6 @@
|
||||
android:accountPreferences="@xml/account_preferences"
|
||||
android:accountType="@string/google_account_type"
|
||||
android:customTokens="true"
|
||||
android:icon="@drawable/auth_gls_ic_google_selected"
|
||||
android:smallIcon="@drawable/auth_gls_ic_google_minitab_selected"
|
||||
android:icon="@drawable/proprietary_auth_gls_ic_google_selected"
|
||||
android:smallIcon="@drawable/proprietary_auth_gls_ic_google_minitab_selected"
|
||||
android:label="@string/google_account_label" />
|
||||
|
@ -16,15 +16,147 @@
|
||||
|
||||
package org.microg.gms.auth;
|
||||
|
||||
import android.accounts.Account;
|
||||
import android.app.Activity;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.BaseAdapter;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.ListView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.google.android.gms.R;
|
||||
|
||||
import org.microg.gms.userinfo.ProfileManager;
|
||||
|
||||
public class AskPermissionActivity extends Activity {
|
||||
private static final String TAG = "GmsAuthAskPermission";
|
||||
private Account account;
|
||||
private String packageName;
|
||||
private String service;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.ask_permission);
|
||||
|
||||
// This makes the dialog take up the full width
|
||||
WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
|
||||
lp.copyFrom(getWindow().getAttributes());
|
||||
lp.width = WindowManager.LayoutParams.MATCH_PARENT;
|
||||
lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
|
||||
getWindow().setAttributes(lp);
|
||||
|
||||
// receive package info
|
||||
PackageManager packageManager = getPackageManager();
|
||||
ApplicationInfo applicationInfo;
|
||||
try {
|
||||
applicationInfo = packageManager.getApplicationInfo(packageName, 0);
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
Log.w(TAG, e);
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
CharSequence appLabel = packageManager.getApplicationLabel(applicationInfo);
|
||||
Drawable appIcon = packageManager.getApplicationIcon(applicationInfo);
|
||||
Bitmap profileIcon = ProfileManager.getProfilePicture(this, account, false);
|
||||
|
||||
if (profileIcon != null) {
|
||||
((ImageView) findViewById(R.id.account_photo)).setImageBitmap(profileIcon);
|
||||
} else {
|
||||
new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
final Bitmap profileIcon = ProfileManager.getProfilePicture(AskPermissionActivity.this, account, true);
|
||||
runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
((ImageView) findViewById(R.id.account_photo)).setImageBitmap(profileIcon);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
|
||||
((ImageView) findViewById(R.id.app_icon)).setImageDrawable(appIcon);
|
||||
((TextView) findViewById(R.id.title)).setText(getString(R.string.ask_permission_title, appLabel));
|
||||
findViewById(android.R.id.button1).setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
onAllow();
|
||||
}
|
||||
});
|
||||
findViewById(android.R.id.button2).setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
onDeny();
|
||||
}
|
||||
});
|
||||
((ListView) findViewById(R.id.permissions)).setAdapter(new PermissionAdapter());
|
||||
}
|
||||
|
||||
public void onAllow() {
|
||||
AuthManager.storePermission(this, account, packageName, service);
|
||||
finish();
|
||||
}
|
||||
|
||||
public void onDeny() {
|
||||
finish();
|
||||
}
|
||||
|
||||
private class PermissionAdapter extends BaseAdapter {
|
||||
|
||||
private boolean isOAuth() {
|
||||
return service.startsWith("oauth2:") || service.startsWith("oauth:");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
if (isOAuth()) {
|
||||
return service.split(" ").length;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getItem(int position) {
|
||||
if (isOAuth()) {
|
||||
String tokens = service.split(":", 2)[1];
|
||||
return tokens.split(" ")[position];
|
||||
}
|
||||
return service;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemId(int position) {
|
||||
return getItem(position).hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
String item = getItem(position);
|
||||
String label = "unknown";
|
||||
if (!isOAuth()) {
|
||||
int stringId = getResources().getIdentifier("permission_service_" + item + "_label", "string", getPackageName());
|
||||
if (stringId != 0) {
|
||||
label = getString(stringId);
|
||||
}
|
||||
}
|
||||
View view = convertView;
|
||||
if (view == null) {
|
||||
view = LayoutInflater.from(AskPermissionActivity.this).inflate(R.layout.ask_permission_list_entry, null);
|
||||
}
|
||||
((TextView)view.findViewById(android.R.id.text1)).setText(label);
|
||||
return view;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,16 +16,12 @@
|
||||
|
||||
package org.microg.gms.auth;
|
||||
|
||||
import android.accounts.Account;
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
import android.util.Log;
|
||||
|
||||
import org.microg.gms.auth.loginservice.GoogleLoginService;
|
||||
import org.microg.gms.common.Utils;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
@ -36,7 +32,6 @@ public class AuthClient {
|
||||
private static final String SERVICE_URL = "https://android.clients.google.com/auth";
|
||||
|
||||
public static AuthResponse request(AuthRequest request) throws IOException {
|
||||
AuthResponse authResponse = new AuthResponse();
|
||||
HttpURLConnection connection = (HttpURLConnection) new URL(SERVICE_URL).openConnection();
|
||||
connection.setRequestMethod("POST");
|
||||
connection.setDoInput(true);
|
||||
@ -60,27 +55,11 @@ public class AuthClient {
|
||||
if (connection.getResponseCode() != 200) {
|
||||
throw new IOException(connection.getResponseMessage());
|
||||
}
|
||||
String result = new String(readStreamToEnd(connection.getInputStream()));
|
||||
String result = new String(Utils.readStreamToEnd(connection.getInputStream()));
|
||||
Log.d(TAG, "-- Response --\n" + result);
|
||||
return AuthResponse.parse(result);
|
||||
}
|
||||
|
||||
protected static byte[] readStreamToEnd(final InputStream is) throws IOException {
|
||||
final ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
if (is != null) {
|
||||
final byte[] buff = new byte[1024];
|
||||
while (true) {
|
||||
final int nb = is.read(buff);
|
||||
if (nb < 0) {
|
||||
break;
|
||||
}
|
||||
bos.write(buff, 0, nb);
|
||||
}
|
||||
is.close();
|
||||
}
|
||||
return bos.toByteArray();
|
||||
}
|
||||
|
||||
public static void request(final AuthRequest request, final GmsAuthCallback callback) {
|
||||
new Thread(new Runnable() {
|
||||
@Override
|
||||
|
@ -21,6 +21,8 @@ import android.accounts.AccountManager;
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
|
||||
import org.microg.gms.common.Utils;
|
||||
|
||||
public class AuthManager {
|
||||
|
||||
private static final String TAG = "GmsAuthManager";
|
||||
@ -36,11 +38,10 @@ public class AuthManager {
|
||||
accountManager.setAuthToken(account, buildTokenKey(packageName, sig, "LSID"), response.LSid);
|
||||
if (response.expiry > 0)
|
||||
accountManager.setUserData(account, buildExpireKey(packageName, sig, service), Long.toString(response.expiry));
|
||||
if (response.auth != null && response.expiry != 0) {
|
||||
if (response.auth != null && response.expiry != 0 && response.storeConsentRemotely) {
|
||||
accountManager.setAuthToken(account, buildTokenKey(packageName, sig, service), response.auth);
|
||||
accountManager.setUserData(account, buildPermKey(packageName, sig, service), "1");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static boolean isPermitted(Context context, Account account, String packageName,
|
||||
@ -60,6 +61,10 @@ public class AuthManager {
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void storePermission(Context context, Account account, String packageName, String service) {
|
||||
storePermission(context, account, packageName, Utils.getFirstPackageSignatureDigest(context, packageName), service);
|
||||
}
|
||||
|
||||
public static void storePermission(Context context, Account account, String packageName,
|
||||
String sig, String service) {
|
||||
AccountManager accountManager = AccountManager.get(context);
|
||||
|
@ -61,7 +61,7 @@ public class AuthResponse {
|
||||
@ResponseField("Expiry")
|
||||
public long expiry = -1;
|
||||
@ResponseField("storeConsentRemotely")
|
||||
public boolean storeConsentRemotely;
|
||||
public boolean storeConsentRemotely = true;
|
||||
|
||||
public static AuthResponse parse(String result) {
|
||||
AuthResponse response = new AuthResponse();
|
||||
|
@ -43,6 +43,7 @@ import org.microg.gms.auth.AuthRequest;
|
||||
import org.microg.gms.auth.AuthResponse;
|
||||
import org.microg.gms.common.Constants;
|
||||
import org.microg.gms.common.Utils;
|
||||
import org.microg.gms.userinfo.ProfileManager;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
@ -218,21 +219,14 @@ public class LoginActivity extends AssistantActivity {
|
||||
}
|
||||
|
||||
private void retrieveGmsKeyUserinfoProfile(final Account account) {
|
||||
final String service = "oauth2:https://www.googleapis.com/auth/userinfo.profile";
|
||||
new AuthRequest().fromContext(this)
|
||||
.appIsGms().callerIsGms()
|
||||
.service(service)
|
||||
.email(account.name)
|
||||
.token(AccountManager.get(this).getPassword(account))
|
||||
.systemPartition()
|
||||
.hasPermission()
|
||||
.getAccountId()
|
||||
ProfileManager.getAuthKeyRequest(this, account)
|
||||
.getResponseAsync(new AuthClient.GmsAuthCallback() {
|
||||
@Override
|
||||
public void onResponse(AuthResponse response) {
|
||||
AuthManager.storeResponse(LoginActivity.this, account,
|
||||
Constants.GMS_PACKAGE_NAME, Constants.GMS_PACKAGE_SIGNATURE_SHA1,
|
||||
service, response);
|
||||
ProfileManager.SERVICE_TOKEN, response);
|
||||
ProfileManager.storeAuthKey(LoginActivity.this, account, response.auth);
|
||||
finish();
|
||||
}
|
||||
|
||||
|
@ -21,6 +21,9 @@ import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.Signature;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.Arrays;
|
||||
@ -39,7 +42,7 @@ public class Utils {
|
||||
return new Build();
|
||||
}
|
||||
|
||||
public static void checkPackage(Context context, String packageName,int callingUid) {
|
||||
public static void checkPackage(Context context, String packageName, int callingUid) {
|
||||
String[] packagesForUid = context.getPackageManager().getPackagesForUid(callingUid);
|
||||
if (packagesForUid != null && !Arrays.asList(packagesForUid).contains(packageName)) {
|
||||
throw new SecurityException("callingUid [" + callingUid + "] is not related to packageName [" + packageName + "]");
|
||||
@ -91,4 +94,20 @@ public class Utils {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static byte[] readStreamToEnd(final InputStream is) throws IOException {
|
||||
final ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
if (is != null) {
|
||||
final byte[] buff = new byte[1024];
|
||||
while (true) {
|
||||
final int nb = is.read(buff);
|
||||
if (nb < 0) {
|
||||
break;
|
||||
}
|
||||
bos.write(buff, 0, nb);
|
||||
}
|
||||
is.close();
|
||||
}
|
||||
return bos.toByteArray();
|
||||
}
|
||||
}
|
||||
|
156
src/org/microg/gms/userinfo/ProfileManager.java
Normal file
@ -0,0 +1,156 @@
|
||||
/*
|
||||
* Copyright 2013-2015 µg Project Team
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.microg.gms.userinfo;
|
||||
|
||||
import android.accounts.Account;
|
||||
import android.accounts.AccountManager;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.util.Base64;
|
||||
import android.util.Log;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import org.microg.gms.auth.AuthManager;
|
||||
import org.microg.gms.auth.AuthRequest;
|
||||
import org.microg.gms.auth.AuthResponse;
|
||||
import org.microg.gms.common.Constants;
|
||||
import org.microg.gms.common.Utils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
|
||||
public class ProfileManager {
|
||||
private static final String TAG = "GmsProfileManager";
|
||||
private static final String PREFERENCES_NAME = "profile_manager";
|
||||
public static final String SERVICE_TOKEN = "oauth2:https://www.googleapis.com/auth/userinfo.profile";
|
||||
|
||||
public static class ProfileInfo {
|
||||
public final String familyName;
|
||||
public final String givenName;
|
||||
public final long id;
|
||||
public final String link;
|
||||
public final String locale;
|
||||
public final String name;
|
||||
public final String picture;
|
||||
|
||||
public ProfileInfo(String familyName, String givenName, long id, String link, String locale, String name, String picture) {
|
||||
this.familyName = familyName;
|
||||
this.givenName = givenName;
|
||||
this.id = id;
|
||||
this.link = link;
|
||||
this.locale = locale;
|
||||
this.name = name;
|
||||
this.picture = picture;
|
||||
}
|
||||
|
||||
public static ProfileInfo parse(byte[] bytes) throws JSONException {
|
||||
return parse(new String(bytes));
|
||||
}
|
||||
|
||||
private static ProfileInfo parse(String info) throws JSONException {
|
||||
return parse(new JSONObject(info));
|
||||
}
|
||||
|
||||
private static ProfileInfo parse(JSONObject info) throws JSONException {
|
||||
return new ProfileInfo(
|
||||
info.has("family_name") ? info.getString("family_name") : null,
|
||||
info.has("given_name") ? info.getString("given_name") : null,
|
||||
info.has("id") ? info.getLong("id") : 0,
|
||||
info.has("link") ? info.getString("link") : null,
|
||||
info.has("locale") ? info.getString("locale") : null,
|
||||
info.has("name") ? info.getString("name") : null,
|
||||
info.has("picture") ? info.getString("picture") : null);
|
||||
}
|
||||
}
|
||||
|
||||
public static SharedPreferences getPreferences(Context context) {
|
||||
return context.getSharedPreferences(PREFERENCES_NAME, Context.MODE_PRIVATE);
|
||||
}
|
||||
|
||||
public static Bitmap getProfilePicture(Context context, Account account, boolean network) {
|
||||
SharedPreferences preferences = getPreferences(context);
|
||||
String picture = preferences.getString("profile_picture", null);
|
||||
if (picture != null) {
|
||||
byte[] bytes = Base64.decode(picture, Base64.DEFAULT);
|
||||
return BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
|
||||
}
|
||||
if (!network) return null;
|
||||
try {
|
||||
URLConnection conn = new URL(getProfileInfo(context, account).picture).openConnection();
|
||||
conn.setDoInput(true);
|
||||
byte[] bytes = Utils.readStreamToEnd(conn.getInputStream());
|
||||
Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
|
||||
if (bitmap != null)
|
||||
preferences.edit().putString("profile_picture", Base64.encodeToString(bytes, Base64.DEFAULT)).commit();
|
||||
return bitmap;
|
||||
} catch (Exception e) {
|
||||
Log.w(TAG, e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static ProfileInfo getProfileInfo(Context context, Account account) {
|
||||
try {
|
||||
URLConnection conn = new URL("https://www.googleapis.com/oauth2/v1/userinfo").openConnection();
|
||||
conn.addRequestProperty("Authorization", "Bearer " + getAuthKey(context, account));
|
||||
conn.setDoInput(true);
|
||||
byte[] bytes = Utils.readStreamToEnd(conn.getInputStream());
|
||||
return ProfileInfo.parse(bytes);
|
||||
} catch (JSONException | IOException e) {
|
||||
Log.w(TAG, e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static AuthRequest getAuthKeyRequest(Context context, Account account) {
|
||||
return new AuthRequest().fromContext(context)
|
||||
.appIsGms().callerIsGms()
|
||||
.service(SERVICE_TOKEN)
|
||||
.email(account.name)
|
||||
.token(AccountManager.get(context).getPassword(account))
|
||||
.systemPartition()
|
||||
.hasPermission()
|
||||
.getAccountId();
|
||||
}
|
||||
|
||||
public static String getAuthKey(Context context, Account account) {
|
||||
String result = context.getSharedPreferences(PREFERENCES_NAME, Context.MODE_PRIVATE)
|
||||
.getString(account.name + "_auth_key", null);
|
||||
if (result == null) {
|
||||
try {
|
||||
AuthResponse response = getAuthKeyRequest(context, account).getResponse();
|
||||
AuthManager.storeResponse(context, account,
|
||||
Constants.GMS_PACKAGE_NAME, Constants.GMS_PACKAGE_SIGNATURE_SHA1,
|
||||
SERVICE_TOKEN, response);
|
||||
result = response.auth;
|
||||
storeAuthKey(context, account, result);
|
||||
} catch (IOException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static void storeAuthKey(Context context, Account account, String key) {
|
||||
context.getSharedPreferences(PREFERENCES_NAME, Context.MODE_PRIVATE).edit()
|
||||
.putString(account.name + "_auth_key", key).commit();
|
||||
}
|
||||
}
|