22 |
23 |
24 | 🚀This app is built for experimental purposes only and has been verified by Play Protect.
25 |
26 | 🚀The app was created using Go Native, which combines enterprise-grade web and native app development. It functions by pasting URLs to build the framework of the entire APK.
27 |
28 | 🥤You can download the APK from the following link: **https://drive.google.com/file/d/11Qf0sL2tkWQYUvrtWU5Mr1LGnjlU-tV_/view?usp=sharing**
29 |
30 | 🥤To build with the SDK, the plugins, and the source code for the app, please refer to the android_source.tar file: **https://drive.google.com/drive/folders/1A1sNHXYyoS8ur6aSPH3BcbS4LTvm51v7?usp=sharing**
31 |
32 |
33 | START🧵
34 |
35 |
36 |
37 | 🚀On the GoNative web page (https://median.co), head to "Median". Create a new project and add the URL that is to be converted into an APK. Then, provide the app name. Finally, save changes to the stage!
38 |
39 | 
40 |
41 | 🚀After completing the Overview stage, proceed to the Branding stage. Your app icon serves as your app’s identity and is utilized on the device home screen and in other locations, such as settings. Upload a PNG or JPG square image to be used as your app's launch icon. The recommended resolution is 1024x1024 pixels.
42 |
43 | 
44 |
45 | 🚀Configure the splash screen that displays while your app initially launches. Splash screen appearance varies between iOS and Android to meet design guidelines for each platform. The splash screen will display until your webpage finishes loading (when the DOMContentLoaded event fires) so that the transition between splash screen and your app is seamless.
46 |
47 | 
48 |
49 | 🚀After making changes to your app configuration press "Rebuild" to rebuild your app files for download. To test your iOS app on a physical device build from source using Xcode, an Apple Developer account is required. Your Android app may be built locally using our included Gradle script or using Android Studio. Set a Bundle ID and Package Name for publishing. These are identifiers for your app registered with the Apple App Store and Google Play Store. They can be changed for licensed apps at any time before your app is published.
50 |
51 | 
52 |
53 | 🚀To debug JavaScript in your web content from our browser-based simulators first rebuild your app with Web Console Logs enabled. Then, on the simulator panel toggle toggle "Debug Mode" and click "Appetize". The JavaScript console for the app will be shown at the bottom of the window that opens. The "Debug Logs" tab will show the native app log output as well as the web console logs. Note: This option builds an unsigned debug build and must be disabled to build a signed APK/AAB for the Google Play Store.
54 |
55 | 
56 |
57 | ⬇️After obtaining the information, return to the top and open the Google Drive link to download the app. Then, "install" it.
58 |
59 |
60 | 
61 |
62 | ⬇️Then it verifies the app to ensure it's safe. After verification, it proceeds to the following steps.
63 |
64 |
65 | 
66 |
67 | ⬇️After the app is deemed safe, you can install it by clicking the "Install" button. That's it! You can now use your own Hugging Face login.
68 |
69 |
70 | 
71 |
72 | ⬇️You can also build the app with the GoNative plugins (Median). You can find the link at the top of the list.
73 |
74 |
75 | ## 💰 Buy me a coffee 🥤
76 | [](https://www.buymeacoffee.com/prithivsakthi)
77 |
78 | Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
79 |
--------------------------------------------------------------------------------
/Hugging Face/app/src/main/java/co/median/android/SegmentedController.java:
--------------------------------------------------------------------------------
1 | package co.median.android;
2 |
3 | import android.content.BroadcastReceiver;
4 | import android.content.Context;
5 | import android.content.Intent;
6 | import android.content.IntentFilter;
7 | import androidx.localbroadcastmanager.content.LocalBroadcastManager;
8 | import android.view.View;
9 | import android.widget.AdapterView;
10 | import android.widget.ArrayAdapter;
11 | import android.widget.Spinner;
12 |
13 | import org.json.JSONObject;
14 |
15 | import java.util.ArrayList;
16 |
17 | import co.median.median_core.AppConfig;
18 |
19 | /**
20 | * Created by weiyin on 12/20/15.
21 | * Copyright 2014 GoNative.io LLC
22 | */
23 | public class SegmentedController implements AdapterView.OnItemSelectedListener {
24 | private MainActivity mainActivity;
25 | private ArrayList labels;
26 | private ArrayList urls;
27 | private int selectedIndex;
28 |
29 | private ArrayAdapter adapter;
30 | private Spinner spinner;
31 |
32 | SegmentedController(MainActivity mainActivity, Spinner spinner) {
33 | this.mainActivity = mainActivity;
34 | this.spinner = spinner;
35 |
36 | this.labels = new ArrayList<>();
37 | this.urls = new ArrayList<>();
38 |
39 | this.spinner.setAdapter(getAdapter());
40 | this.spinner.setOnItemSelectedListener(this);
41 |
42 | BroadcastReceiver messageReceiver = new BroadcastReceiver() {
43 | @Override
44 | public void onReceive(Context context, Intent intent) {
45 | if (intent == null || intent.getAction() == null) return;
46 |
47 | if (intent.getAction().equals(AppConfig.PROCESSED_SEGMENTED_CONTROL)) {
48 | updateSegmentedControl();
49 | }
50 | }
51 | };
52 | LocalBroadcastManager.getInstance(this.mainActivity).registerReceiver(
53 | messageReceiver, new IntentFilter(AppConfig.PROCESSED_SEGMENTED_CONTROL));
54 |
55 | updateSegmentedControl();
56 | }
57 |
58 | private void updateSegmentedControl() {
59 | this.labels.clear();
60 | this.urls.clear();
61 | this.selectedIndex = -1;
62 |
63 | AppConfig appConfig = AppConfig.getInstance(mainActivity);
64 | if (appConfig.segmentedControl == null) return;
65 |
66 | for (int i = 0; i < appConfig.segmentedControl.size(); i++) {
67 | JSONObject item = appConfig.segmentedControl.get(i);
68 |
69 | String label = item.optString("label", "Invalid");
70 | String url = item.optString("url", "");
71 | Boolean selected = item.optBoolean("selected");
72 |
73 | this.labels.add(i, label);
74 | this.urls.add(i, url);
75 | if (selected) this.selectedIndex = i;
76 | }
77 |
78 | mainActivity.runOnUiThread(new Runnable() {
79 | @Override
80 | public void run() {
81 | if (selectedIndex > -1) {
82 | spinner.setSelection(selectedIndex);
83 | }
84 |
85 | if (labels.size() > 0) {
86 | spinner.setVisibility(View.VISIBLE);
87 | } else {
88 | spinner.setVisibility(View.GONE);
89 | }
90 |
91 | adapter.notifyDataSetChanged();
92 | }
93 | });
94 |
95 | }
96 |
97 | private ArrayAdapter getAdapter() {
98 | if (this.adapter != null) {
99 | return this.adapter;
100 | }
101 |
102 | ArrayAdapter adapter = new ArrayAdapter<>(mainActivity,
103 | android.R.layout.simple_spinner_item, labels);
104 | adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
105 | this.adapter = adapter;
106 | return adapter;
107 | }
108 |
109 | @Override
110 | public void onItemSelected(AdapterView> parent, View view, int position, long id) {
111 | // only load if selection has changed
112 | if (position != selectedIndex) {
113 | String url = urls.get(position);
114 |
115 | if (url != null && url.length() > 0) {
116 | mainActivity.loadUrl(url);
117 | }
118 |
119 | mainActivity.closeDrawers();
120 | selectedIndex = position;
121 | }
122 | }
123 |
124 | @Override
125 | public void onNothingSelected(AdapterView> parent) {
126 | // do nothing
127 | }
128 | }
129 |
--------------------------------------------------------------------------------
/Hugging Face/app/src/main/java/co/median/android/ProfilePicker.java:
--------------------------------------------------------------------------------
1 | package co.median.android;
2 |
3 | import androidx.annotation.NonNull;
4 | import android.view.View;
5 | import android.view.ViewGroup;
6 | import android.webkit.JavascriptInterface;
7 | import android.widget.AdapterView;
8 | import android.widget.ArrayAdapter;
9 | import android.widget.Spinner;
10 | import android.widget.TextView;
11 |
12 | import org.json.JSONArray;
13 | import org.json.JSONException;
14 | import org.json.JSONObject;
15 |
16 | import java.util.ArrayList;
17 |
18 | import co.median.median_core.GNLog;
19 |
20 | /**
21 | * Created by weiyin on 5/9/14.
22 | */
23 | public class ProfilePicker implements AdapterView.OnItemSelectedListener {
24 | private static final String TAG = ProfilePicker.class.getName();
25 |
26 | private MainActivity mainActivity;
27 | private JSONArray json;
28 | private ArrayList names;
29 | private ArrayList links;
30 | private int selectedIndex;
31 |
32 | private ArrayAdapter adapter;
33 | private Spinner spinner;
34 | private ProfileJsBridge profileJsBridge;
35 |
36 | public ProfilePicker(MainActivity mainActivity, Spinner spinner) {
37 | this.mainActivity = mainActivity;
38 | this.spinner = spinner;
39 | this.names = new ArrayList<>();
40 | this.links = new ArrayList<>();
41 | this.spinner.setAdapter(getAdapter());
42 | this.spinner.setOnItemSelectedListener(this);
43 | this.profileJsBridge = new ProfileJsBridge();
44 | }
45 |
46 | private void parseJson(String s){
47 | try {
48 | json = new JSONArray(s);
49 | this.names.clear();
50 | this.links.clear();
51 |
52 | for (int i = 0; i < json.length(); i++) {
53 | JSONObject item = json.getJSONObject(i);
54 |
55 | this.names.add(item.optString("name", ""));
56 | this.links.add(item.optString("link", ""));
57 |
58 | if (item.optBoolean("selected", false)){
59 | selectedIndex = i;
60 | }
61 | }
62 |
63 | mainActivity.runOnUiThread(new Runnable() {
64 | public void run() {
65 | if (selectedIndex < ProfilePicker.this.names.size()) {
66 | ProfilePicker.this.spinner.setSelection(selectedIndex);
67 | }
68 | if (ProfilePicker.this.json != null &&
69 | ProfilePicker.this.json.length() > 0)
70 | ProfilePicker.this.spinner.setVisibility(View.VISIBLE);
71 | else
72 | ProfilePicker.this.spinner.setVisibility(View.GONE);
73 | getAdapter().notifyDataSetChanged();
74 | }
75 | });
76 |
77 | } catch (JSONException e) {
78 | GNLog.getInstance().logError(TAG, e.getMessage(), e);
79 | }
80 | }
81 |
82 | private ArrayAdapter getAdapter(){
83 | if (adapter == null) {
84 |
85 | adapter = new ArrayAdapter(mainActivity, R.layout.profile_picker_dropdown, names) {
86 | @NonNull
87 | @Override
88 | public View getView(int position, View convertView, @NonNull ViewGroup parent) {
89 | TextView view = (TextView) super.getView(position, convertView, parent);
90 | view.setTextColor(mainActivity.getResources().getColor(R.color.sidebarForeground));
91 | return view;
92 | }
93 |
94 | @Override
95 | public View getDropDownView(int position, View convertView, @NonNull ViewGroup parent) {
96 | TextView view = (TextView) super.getDropDownView(position, convertView, parent);
97 | view.setTextColor(mainActivity.getResources().getColor(R.color.sidebarForeground));
98 | return view;
99 | }
100 | };
101 | }
102 |
103 | return adapter;
104 | }
105 |
106 | public void onItemSelected(AdapterView> parent, View view, int position, long id) {
107 | // only load if selection has changed
108 | if (position != selectedIndex) {
109 | mainActivity.loadUrl(links.get(position));
110 | mainActivity.closeDrawers();
111 | selectedIndex = position;
112 | }
113 | }
114 |
115 | public void onNothingSelected(AdapterView> parent) {
116 | // do nothing
117 | }
118 |
119 | public ProfileJsBridge getProfileJsBridge() {
120 | return profileJsBridge;
121 | }
122 |
123 | public class ProfileJsBridge {
124 | @JavascriptInterface
125 | public void parseJson(String s) {
126 | ProfilePicker.this.parseJson(s);
127 | }
128 | }
129 | }
130 |
--------------------------------------------------------------------------------
/Hugging Face/app/src/androidTest/assets/appConfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "general": {
3 | "userAgentAdd": "gonative",
4 | "initialUrl": "https://gonative.io",
5 | "appName": "GoNative.io"
6 | },
7 | "navigation": {
8 | "androidPullToRefresh": true,
9 | "sidebarNavigation": {
10 | "sidebarEnabledRegex": null,
11 | "menus": [{
12 | "name": "default",
13 | "items": [{
14 | "url": "https://gonative.io",
15 | "label": "Home",
16 | "subLinks": []
17 | }, {
18 | "url": "https://gonative.io/about",
19 | "label": "About",
20 | "subLinks": []
21 | }, {
22 | "url": "https://gonative.io/examples",
23 | "label": "Examples",
24 | "subLinks": []
25 | }],
26 | "active": true
27 | }]
28 | },
29 | "tabNavigation": {
30 | "tabSelectionConfig": [{
31 | "id": "1",
32 | "regex": ".*about.*"
33 | }],
34 | "tabMenus": [{
35 | "id": "1",
36 | "items": [{
37 | "icon": "fa-cloud",
38 | "label": "Tab 1",
39 | "url": "https://www.gonative.io/pricing"
40 | }, {
41 | "icon": "fa-globe",
42 | "label": "Tab 2",
43 | "url": "https://www.gonative.io/examples"
44 | }, {
45 | "icon": "fa-users",
46 | "label": "Tab 3",
47 | "url": "javascript:alert('You selected tab 3. These tabs are only shown on the about page')"
48 | }]
49 | }],
50 | "active": true
51 | },
52 | "actionConfig": {
53 | "active": true,
54 | "actions": [{
55 | "id": "exampleActions",
56 | "items": [{
57 | "label": "Globe",
58 | "icon": "fa-globe",
59 | "url": "javascript:alert('You tapped the globe! It only appears on the Examples page')"
60 | }]
61 | }],
62 | "actionSelection": [{
63 | "regex": ".*/examples.*",
64 | "id": "exampleActions"
65 | }]
66 | },
67 | "regexInternalExternal": {
68 | "rules": [{
69 | "regex": "https?://([-\\w]+\\.)*facebook\\.com/login.php.*",
70 | "internal": true
71 | }, {
72 | "regex": "https?://([-\\w]+\\.)*facebook\\.com/pages/.*",
73 | "internal": false
74 | }, {
75 | "regex": "https?://([-\\w]+\\.)*facebook\\.com/sharer\\.php.*",
76 | "internal": false
77 | }, {
78 | "regex": "https?://([-\\w]+\\.)*plus\\.google\\.com/share.*",
79 | "internal": false
80 | }, {
81 | "regex": "https?://([-\\w]+\\.)*twitter\\.com/intent/.*",
82 | "internal": false
83 | }, {
84 | "regex": "https?://([-\\w]+\\.)*gonative\\.io/?.*",
85 | "internal": true
86 | }, {
87 | "regex": "https?://([-\\w]+\\.)*google\\.com/?.*",
88 | "internal": true
89 | }, {
90 | "regex": "https://gonative-test-web.web.app/.*",
91 | "internal": true
92 | },
93 | {
94 | "regex": "https://us-central1-gn-test-firebase-test-lab.cloudfunctions.net/.*",
95 | "internal": true
96 | }],
97 | "active": true
98 | },
99 | "redirects": [{
100 | "from": "https://example.com/from/",
101 | "to": "https://example.com/to/"
102 | }]
103 | },
104 | "forms": {
105 | "search": {
106 | "active": true,
107 | "searchTemplateURL": "https://us-central1-gn-test-firebase-test-lab.cloudfunctions.net/gnTestSearch?q="
108 | }
109 | },
110 | "styling": {
111 | "showActionBar": true,
112 | "showNavigationBar": true,
113 | "iosTitleColor": "#333333",
114 | "iosTintColor": "#0091fe",
115 | "androidTheme": "Light.DarkActionBar",
116 | "androidSidebarBackgroundColor": "#111111",
117 | "androidSidebarForegroundColor": "#d0d0d0",
118 | "androidHideTitleInActionBar": false,
119 | "androidPullToRefreshColor": "#333333",
120 | "androidTabBarBackgroundColor": "#fefefe",
121 | "androidTabBarTextColor": "#747474",
122 | "androidTabBarIndicatorColorx": "#2f79fe",
123 | "androidShowSplash": true,
124 | "androidShowSplashMaxTime": null,
125 | "androidShowSplashForceTime": null,
126 | "disableAnimations": false,
127 | "menuAnimationDuration": 0.15,
128 | "transitionInteractiveDelayMax": 0.2
129 | },
130 | "permissions": {
131 | "usesGeolocation": false,
132 | "androidDownloadToPublicStorage": false
133 | },
134 | "services": {
135 | "oneSignal": {
136 | "active": false,
137 | "applicationId": ""
138 | },
139 | "facebook": {
140 | "active": false,
141 | "appId": "",
142 | "displayName": ""
143 | },
144 | "registration": {
145 | "active": false,
146 | "endpoints": [{
147 | "url": "https://gonative.io/example_push_endpoint",
148 | "dataType": "onesignal",
149 | "urlRegex": ".*/loginfinished"
150 | }]
151 | }
152 | }
153 | }
154 |
--------------------------------------------------------------------------------
/Hugging Face/app/src/normal/java/co/median/android/GoNativeWebviewClient.java:
--------------------------------------------------------------------------------
1 | package co.median.android;
2 |
3 | import android.annotation.TargetApi;
4 | import android.content.Context;
5 | import android.graphics.Bitmap;
6 | import android.net.Uri;
7 | import android.net.http.SslError;
8 | import android.os.Build;
9 | import android.os.Message;
10 | import android.webkit.ClientCertRequest;
11 | import android.webkit.SslErrorHandler;
12 | import android.webkit.WebResourceError;
13 | import android.webkit.WebResourceRequest;
14 | import android.webkit.WebResourceResponse;
15 | import android.webkit.WebView;
16 | import android.webkit.WebViewClient;
17 |
18 | import androidx.annotation.RequiresApi;
19 |
20 | import co.median.median_core.GoNativeWebviewInterface;
21 |
22 | /**
23 | * Created by weiyin on 9/9/15.
24 | */
25 | public class GoNativeWebviewClient extends WebViewClient{
26 | private static final String TAG = GoNativeWebviewClient.class.getName();
27 | private UrlNavigation urlNavigation;
28 | private Context context;
29 |
30 | public GoNativeWebviewClient(MainActivity mainActivity, UrlNavigation urlNavigation) {
31 | this.urlNavigation = urlNavigation;
32 | this.context = mainActivity;
33 | }
34 |
35 | @Override
36 | public boolean shouldOverrideUrlLoading(WebView view, String url) {
37 | return urlNavigation.shouldOverrideUrlLoading((GoNativeWebviewInterface)view, url);
38 | }
39 |
40 | public boolean shouldOverrideUrlLoading(WebView view, String url, boolean isReload) {
41 | return urlNavigation.shouldOverrideUrlLoading((GoNativeWebviewInterface)view, url, isReload, false);
42 | }
43 |
44 | @Override
45 | public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
46 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
47 | Uri uri = request.getUrl();
48 | return urlNavigation.shouldOverrideUrlLoading((GoNativeWebviewInterface)view, uri.toString(), false, request.isRedirect());
49 | }
50 | return super.shouldOverrideUrlLoading(view, request);
51 | }
52 |
53 | @Override
54 | public void onPageStarted(WebView view, String url, Bitmap favicon) {
55 | super.onPageStarted(view, url, favicon);
56 |
57 | urlNavigation.onPageStarted(url);
58 | }
59 |
60 | @Override
61 | public void onPageFinished(WebView view, String url) {
62 | super.onPageFinished(view, url);
63 |
64 | urlNavigation.onPageFinished((GoNativeWebviewInterface)view, url);
65 | }
66 |
67 | @Override
68 | public void onFormResubmission(WebView view, Message dontResend, Message resend) {
69 | urlNavigation.onFormResubmission((GoNativeWebviewInterface)view, dontResend, resend);
70 | }
71 |
72 | @Override
73 | public void doUpdateVisitedHistory(WebView view, String url, boolean isReload) {
74 | urlNavigation.doUpdateVisitedHistory((GoNativeWebviewInterface)view, url, isReload);
75 | }
76 |
77 | @Override
78 | public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
79 | urlNavigation.onReceivedError((GoNativeWebviewInterface) view, errorCode, description, failingUrl);
80 | }
81 |
82 | @TargetApi(Build.VERSION_CODES.M)
83 | @Override
84 | public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
85 | urlNavigation.onReceivedError((GoNativeWebviewInterface) view, error.getErrorCode(),
86 | error.getDescription().toString(), request.getUrl().toString());
87 | }
88 |
89 | @Override
90 | public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
91 | handler.cancel();
92 | urlNavigation.onReceivedSslError(error, view.getUrl());
93 | }
94 |
95 | @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
96 | @Override
97 | public void onReceivedClientCertRequest(WebView view, ClientCertRequest request) {
98 | urlNavigation.onReceivedClientCertRequest(view.getUrl(), request);
99 | }
100 |
101 | @Override
102 | public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
103 | return urlNavigation.interceptHtml((LeanWebView)view, url);
104 | }
105 |
106 | @TargetApi(Build.VERSION_CODES.LOLLIPOP)
107 | @Override
108 | public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
109 |
110 | WebResourceResponse wr = ((GoNativeApplication) context.getApplicationContext()).mBridge.interceptHtml((MainActivity) context, request);
111 | if (wr != null) {
112 | return wr;
113 | }
114 |
115 | String method = request.getMethod();
116 | if (method == null || !method.equalsIgnoreCase("GET")) return null;
117 |
118 | android.net.Uri uri = request.getUrl();
119 | if (uri == null || !uri.getScheme().startsWith("http")) return null;
120 |
121 | return shouldInterceptRequest(view, uri.toString());
122 | }
123 | }
124 |
--------------------------------------------------------------------------------
/Hugging Face/app/src/main/java/co/median/android/LoginManager.java:
--------------------------------------------------------------------------------
1 | package co.median.android;
2 |
3 | import android.content.Context;
4 | import android.os.AsyncTask;
5 |
6 | import org.json.JSONObject;
7 |
8 | import java.lang.ref.WeakReference;
9 | import java.net.HttpURLConnection;
10 | import java.net.URL;
11 | import java.util.List;
12 | import java.util.Observable;
13 | import java.util.regex.Pattern;
14 |
15 | import co.median.median_core.AppConfig;
16 | import co.median.median_core.GNLog;
17 |
18 | /**
19 | * Created by weiyin on 3/16/14.
20 | */
21 | public class LoginManager extends Observable {
22 | private static final String TAG = LoginManager.class.getName();
23 |
24 | private Context context;
25 | private CheckRedirectionTask task = null;
26 |
27 | private boolean loggedIn = false;
28 |
29 | LoginManager(Context context) {
30 | this.context = context;
31 | checkLogin();
32 | }
33 |
34 | public void checkLogin() {
35 | if (task != null)
36 | task.cancel(true);
37 |
38 | String loginDetectionUrl = AppConfig.getInstance(context).loginDetectionUrl;
39 | if (loginDetectionUrl == null) {
40 | return;
41 | }
42 |
43 | task = new CheckRedirectionTask(this);
44 | task.execute(AppConfig.getInstance(context).loginDetectionUrl);
45 | }
46 |
47 | public boolean isLoggedIn() {
48 | return loggedIn;
49 | }
50 |
51 |
52 | private static class CheckRedirectionTask extends AsyncTask {
53 | private WeakReference loginManagerReference;
54 |
55 | public CheckRedirectionTask(LoginManager loginManager) {
56 | this.loginManagerReference = new WeakReference<>(loginManager);
57 | }
58 |
59 | @Override
60 | protected String doInBackground(String... urls){
61 | LoginManager loginManager = loginManagerReference.get();
62 | if (loginManager == null) return null;
63 |
64 | try {
65 | URL parsedUrl = new URL(urls[0]);
66 | HttpURLConnection connection = null;
67 | boolean wasRedirected;
68 | int numRedirects = 0;
69 | do {
70 | if (connection != null)
71 | connection.disconnect();
72 |
73 | connection = (HttpURLConnection) parsedUrl.openConnection();
74 | connection.setInstanceFollowRedirects(true);
75 | connection.setRequestProperty("User-Agent", AppConfig.getInstance(loginManager.context).userAgent);
76 |
77 | connection.connect();
78 | int responseCode = connection.getResponseCode();
79 |
80 | if (responseCode == HttpURLConnection.HTTP_MOVED_PERM ||
81 | responseCode == HttpURLConnection.HTTP_MOVED_TEMP) {
82 | wasRedirected = true;
83 | parsedUrl = new URL(parsedUrl, connection.getHeaderField("Location"));
84 | numRedirects++;
85 | } else {
86 | wasRedirected = false;
87 | }
88 | } while (!isCancelled() && wasRedirected && numRedirects < 10);
89 |
90 | String finalUrl = connection.getURL().toString();
91 | connection.disconnect();
92 | return finalUrl;
93 |
94 | } catch (Exception e) {
95 | GNLog.getInstance().logError(TAG, e.getMessage(), e);
96 | return null;
97 | }
98 | }
99 |
100 | @Override
101 | protected void onPostExecute(String finalUrl) {
102 | LoginManager loginManager = loginManagerReference.get();
103 | if (loginManager == null) return;
104 |
105 | UrlInspector.getInstance().inspectUrl(finalUrl);
106 | String loginStatus;
107 |
108 | if (finalUrl == null) {
109 | loginManager.loggedIn = false;
110 | loginStatus = "default";
111 | loginManager.setChanged();
112 | loginManager.notifyObservers();
113 | return;
114 | }
115 |
116 | // iterate through loginDetectionRegexes
117 | AppConfig appConfig = AppConfig.getInstance(loginManager.context);
118 |
119 | List regexes = appConfig.loginDetectRegexes;
120 | for (int i = 0; i < regexes.size(); i++) {
121 | Pattern regex = regexes.get(i);
122 | if (regex.matcher(finalUrl).matches()) {
123 | JSONObject entry = appConfig.loginDetectLocations.get(i);
124 | loginManager.loggedIn = entry.optBoolean("loggedIn", false);
125 |
126 | loginStatus = AppConfig.optString(entry, "menuName");
127 | if (loginStatus == null) loginStatus = loginManager.loggedIn ? "loggedIn" : "default";
128 |
129 | loginManager.setChanged();
130 | loginManager.notifyObservers();
131 | break;
132 | }
133 | }
134 | }
135 |
136 | }
137 | }
138 |
--------------------------------------------------------------------------------
/Hugging Face/app/src/main/java/co/median/android/GoNativeWindowManager.java:
--------------------------------------------------------------------------------
1 | package co.median.android;
2 |
3 | import android.text.TextUtils;
4 |
5 | import java.util.LinkedHashMap;
6 | import java.util.Map;
7 |
8 | public class GoNativeWindowManager {
9 | private final LinkedHashMap windows;
10 | private ExcessWindowsClosedListener excessWindowsClosedListener;
11 |
12 | public GoNativeWindowManager() {
13 | windows = new LinkedHashMap<>();
14 | }
15 |
16 | public void addNewWindow(String activityId, boolean isRoot) {
17 | this.windows.put(activityId, new ActivityWindow(activityId, isRoot));
18 | }
19 |
20 | public void removeWindow(String activityId) {
21 | this.windows.remove(activityId);
22 |
23 | if (excessWindowsClosedListener != null && windows.size() <= 1) {
24 | excessWindowsClosedListener.onAllExcessWindowClosed();
25 | }
26 | }
27 |
28 | public void setOnExcessWindowClosedListener(ExcessWindowsClosedListener listener) {
29 | this.excessWindowsClosedListener = listener;
30 | }
31 |
32 | public ActivityWindow getActivityWindowInfo(String activityId) {
33 | return windows.get(activityId);
34 | }
35 |
36 | public void setUrlLevel(String activityId, int urlLevel) {
37 | ActivityWindow window = windows.get(activityId);
38 | if (window != null) {
39 | window.setUrlLevels(urlLevel, window.parentUrlLevel);
40 | }
41 | }
42 |
43 | public int getUrlLevel(String activityId) {
44 | ActivityWindow window = windows.get(activityId);
45 | if (window != null) {
46 | return window.urlLevel;
47 | }
48 | return -1;
49 | }
50 |
51 | public void setParentUrlLevel(String activityId, int parentLevel) {
52 | ActivityWindow window = windows.get(activityId);
53 | if (window != null) {
54 | window.setUrlLevels(window.urlLevel, parentLevel);
55 | }
56 | }
57 |
58 | public int getParentUrlLevel(String activityId) {
59 | ActivityWindow window = windows.get(activityId);
60 | if (window != null) {
61 | return window.parentUrlLevel;
62 | }
63 | return -1;
64 | }
65 |
66 | public void setUrlLevels(String activityId, int urlLevel, int parentLevel) {
67 | ActivityWindow window = windows.get(activityId);
68 | if (window != null) {
69 | window.setUrlLevels(urlLevel, parentLevel);
70 | }
71 | }
72 |
73 | public boolean isRoot(String activityId) {
74 | ActivityWindow window = windows.get(activityId);
75 | if (window != null) {
76 | return window.isRoot;
77 | }
78 | return false;
79 | }
80 |
81 | public void setAsNewRoot(String activityId) {
82 | for (Map.Entry entry : windows.entrySet()) {
83 | ActivityWindow window = entry.getValue();
84 | if (TextUtils.equals(activityId, entry.getKey())) {
85 | window.isRoot = true;
86 | } else {
87 | window.isRoot = false;
88 | }
89 | }
90 | }
91 |
92 | public void setIgnoreInterceptMaxWindows(String activityId, boolean ignore) {
93 | ActivityWindow window = windows.get(activityId);
94 | if (window != null) {
95 | window.ignoreInterceptMaxWindows = ignore;
96 | }
97 | }
98 |
99 | public boolean isIgnoreInterceptMaxWindows(String activityId) {
100 | ActivityWindow window = windows.get(activityId);
101 | if (window != null) {
102 | return window.ignoreInterceptMaxWindows;
103 | }
104 | return false;
105 | }
106 |
107 | public int getWindowCount() {
108 | return windows.size();
109 | }
110 |
111 | // Returns ID of the next window after root as Excess window
112 | public String getExcessWindow() {
113 | for (Map.Entry entry : windows.entrySet()) {
114 | ActivityWindow window = entry.getValue();
115 | if (window.isRoot) continue;
116 | return window.id;
117 | }
118 | return null;
119 | }
120 |
121 | public static class ActivityWindow {
122 | private final String id;
123 | private boolean isRoot;
124 | private int urlLevel;
125 | private int parentUrlLevel;
126 | private boolean ignoreInterceptMaxWindows;
127 |
128 | ActivityWindow(String id, boolean isRoot) {
129 | this.id = id;
130 | this.isRoot = isRoot;
131 | this.urlLevel = -1;
132 | this.parentUrlLevel = -1;
133 | }
134 |
135 | public void setUrlLevels(int urlLevel, int parentUrlLevel) {
136 | this.urlLevel = urlLevel;
137 | this.parentUrlLevel = parentUrlLevel;
138 | }
139 |
140 | @Override
141 | public String toString() {
142 | return "id=" + id + "\n" +
143 | "isRoot=" + isRoot + "\n" +
144 | "urlLevel=" + urlLevel + "\n" +
145 | "parentUrlLevel=" + parentUrlLevel;
146 | }
147 | }
148 |
149 |
150 | interface ExcessWindowsClosedListener {
151 | void onAllExcessWindowClosed();
152 | }
153 | }
154 |
--------------------------------------------------------------------------------
/Hugging Face/app/src/normal/java/co/median/android/WebkitCookieManagerProxy.java:
--------------------------------------------------------------------------------
1 | package co.median.android;
2 |
3 | import java.io.IOException;
4 | import java.net.CookiePolicy;
5 | import java.net.CookieStore;
6 | import java.net.HttpCookie;
7 | import java.net.URI;
8 | import java.util.Arrays;
9 | import java.util.Calendar;
10 | import java.util.Date;
11 | import java.util.List;
12 | import java.util.Map;
13 |
14 | import co.median.median_core.AppConfig;
15 | import co.median.median_core.LeanUtils;
16 |
17 | // this syncs cookies between webkit (webview) and java.net classes
18 | public class WebkitCookieManagerProxy extends java.net.CookieManager {
19 | private static final String TAG = WebkitCookieManagerProxy.class.getName();
20 | private android.webkit.CookieManager webkitCookieManager;
21 |
22 | public WebkitCookieManagerProxy()
23 | {
24 | this(null, null);
25 | }
26 |
27 | WebkitCookieManagerProxy(CookieStore store, CookiePolicy cookiePolicy)
28 | {
29 | super(null, cookiePolicy);
30 |
31 | this.webkitCookieManager = android.webkit.CookieManager.getInstance();
32 | }
33 |
34 | // java.net.CookieManager overrides
35 | @Override
36 | public void put(URI uri, Map> responseHeaders) throws IOException
37 | {
38 | // make sure our args are valid
39 | if ((uri == null) || (responseHeaders == null)) return;
40 |
41 | // save our url once
42 | String url = uri.toString();
43 |
44 | String expiryString = null;
45 | int sessionExpiry = AppConfig.getInstance(null).forceSessionCookieExpiry;
46 |
47 | // go over the headers
48 | for (String headerKey : responseHeaders.keySet())
49 | {
50 | // ignore headers which aren't cookie related
51 | if ((headerKey == null) || !headerKey.equalsIgnoreCase("Set-Cookie")) continue;
52 |
53 | // process each of the headers
54 | for (String headerValue : responseHeaders.get(headerKey))
55 | {
56 | boolean passOriginalHeader = true;
57 | if (sessionExpiry > 0) {
58 | List cookies = HttpCookie.parse(headerValue);
59 | for (HttpCookie cookie : cookies) {
60 | if (cookie.getMaxAge() < 0 || cookie.getDiscard()) {
61 | // this is a session cookie. Modify it and pass it to the webview.
62 | cookie.setMaxAge(sessionExpiry);
63 | cookie.setDiscard(false);
64 | if (expiryString == null) {
65 | Calendar calendar = Calendar.getInstance();
66 | calendar.add(Calendar.SECOND, sessionExpiry);
67 | Date expiryDate = calendar.getTime();
68 | expiryString = "; expires=" + LeanUtils.formatDateForCookie(expiryDate) +
69 | "; Max-Age=" + Integer.toString(sessionExpiry);
70 | }
71 |
72 | StringBuilder newHeader = new StringBuilder();
73 | newHeader.append(cookie.toString());
74 | newHeader.append(expiryString);
75 | if (cookie.getPath() != null) {
76 | newHeader.append("; path=");
77 | newHeader.append(cookie.getPath());
78 | }
79 | if (cookie.getDomain() != null) {
80 | newHeader.append("; domain=");
81 | newHeader.append(cookie.getDomain());
82 | }
83 | if (cookie.getSecure()) {
84 | newHeader.append("; secure");
85 | }
86 |
87 | this.webkitCookieManager.setCookie(url, newHeader.toString());
88 | passOriginalHeader = false;
89 | }
90 | }
91 | }
92 |
93 | if (passOriginalHeader) this.webkitCookieManager.setCookie(url, headerValue);
94 | }
95 | }
96 | }
97 |
98 | @Override
99 | public Map> get(URI uri, Map> requestHeaders) throws IOException
100 | {
101 | // make sure our args are valid
102 | if ((uri == null) || (requestHeaders == null)) throw new IllegalArgumentException("Argument is null");
103 |
104 | // save our url once
105 | String url = uri.toString();
106 |
107 | // prepare our response
108 | Map> res = new java.util.HashMap>();
109 |
110 | // get the cookie
111 | String cookie = this.webkitCookieManager.getCookie(url);
112 |
113 | // return it
114 | if (cookie != null) res.put("Cookie", Arrays.asList(cookie));
115 | return res;
116 | }
117 |
118 | @Override
119 | public CookieStore getCookieStore()
120 | {
121 | // we don't want anyone to work with this cookie store directly
122 | // throw new UnsupportedOperationException();
123 | return null;
124 | }
125 |
126 | }
127 |
--------------------------------------------------------------------------------
/Hugging Face/app/src/main/java/co/median/android/widget/CircleImageView.java:
--------------------------------------------------------------------------------
1 | package co.median.android.widget;
2 |
3 | import android.content.Context;
4 | import android.graphics.Canvas;
5 | import android.graphics.Color;
6 | import android.graphics.Paint;
7 | import android.graphics.RadialGradient;
8 | import android.graphics.Shader;
9 | import android.graphics.drawable.ShapeDrawable;
10 | import android.graphics.drawable.shapes.OvalShape;
11 | import android.view.View;
12 | import android.view.animation.Animation;
13 |
14 | import androidx.core.content.ContextCompat;
15 | import androidx.core.view.ViewCompat;
16 |
17 | /**
18 | * Private class created to work around issues with AnimationListeners being
19 | * called before the animation is actually complete and support shadows on older
20 | * platforms.
21 | */
22 | class CircleImageView extends androidx.appcompat.widget.AppCompatImageView {
23 |
24 | private static final int KEY_SHADOW_COLOR = 0x1E000000;
25 | private static final int FILL_SHADOW_COLOR = 0x3D000000;
26 | // PX
27 | private static final float X_OFFSET = 0f;
28 | private static final float Y_OFFSET = 1.75f;
29 | private static final float SHADOW_RADIUS = 3.5f;
30 | private static final int SHADOW_ELEVATION = 4;
31 |
32 | private Animation.AnimationListener mListener;
33 | int mShadowRadius;
34 |
35 | CircleImageView(Context context, int color) {
36 | super(context);
37 | final float density = getContext().getResources().getDisplayMetrics().density;
38 | final int shadowYOffset = (int) (density * Y_OFFSET);
39 | final int shadowXOffset = (int) (density * X_OFFSET);
40 |
41 | mShadowRadius = (int) (density * SHADOW_RADIUS);
42 |
43 | ShapeDrawable circle;
44 | if (elevationSupported()) {
45 | circle = new ShapeDrawable(new OvalShape());
46 | ViewCompat.setElevation(this, SHADOW_ELEVATION * density);
47 | } else {
48 | OvalShape oval = new CircleImageView.OvalShadow(mShadowRadius);
49 | circle = new ShapeDrawable(oval);
50 | setLayerType(View.LAYER_TYPE_SOFTWARE, circle.getPaint());
51 | circle.getPaint().setShadowLayer(mShadowRadius, shadowXOffset, shadowYOffset,
52 | KEY_SHADOW_COLOR);
53 | final int padding = mShadowRadius;
54 | // set padding so the inner image sits correctly within the shadow.
55 | setPadding(padding, padding, padding, padding);
56 | }
57 | circle.getPaint().setColor(color);
58 | ViewCompat.setBackground(this, circle);
59 | }
60 |
61 | private boolean elevationSupported() {
62 | return android.os.Build.VERSION.SDK_INT >= 21;
63 | }
64 |
65 | @Override
66 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
67 | super.onMeasure(widthMeasureSpec, heightMeasureSpec);
68 | if (!elevationSupported()) {
69 | setMeasuredDimension(getMeasuredWidth() + mShadowRadius * 2, getMeasuredHeight()
70 | + mShadowRadius * 2);
71 | }
72 | }
73 |
74 | public void setAnimationListener(Animation.AnimationListener listener) {
75 | mListener = listener;
76 | }
77 |
78 | @Override
79 | public void onAnimationStart() {
80 | super.onAnimationStart();
81 | if (mListener != null) {
82 | mListener.onAnimationStart(getAnimation());
83 | }
84 | }
85 |
86 | @Override
87 | public void onAnimationEnd() {
88 | super.onAnimationEnd();
89 | if (mListener != null) {
90 | mListener.onAnimationEnd(getAnimation());
91 | }
92 | }
93 |
94 | /**
95 | * Update the background color of the circle image view.
96 | *
97 | * @param colorRes Id of a color resource.
98 | */
99 | public void setBackgroundColorRes(int colorRes) {
100 | setBackgroundColor(ContextCompat.getColor(getContext(), colorRes));
101 | }
102 |
103 | @Override
104 | public void setBackgroundColor(int color) {
105 | if (getBackground() instanceof ShapeDrawable) {
106 | ((ShapeDrawable) getBackground()).getPaint().setColor(color);
107 | }
108 | }
109 |
110 | private class OvalShadow extends OvalShape {
111 | private RadialGradient mRadialGradient;
112 | private Paint mShadowPaint;
113 |
114 | OvalShadow(int shadowRadius) {
115 | super();
116 | mShadowPaint = new Paint();
117 | mShadowRadius = shadowRadius;
118 | updateRadialGradient((int) rect().width());
119 | }
120 |
121 | @Override
122 | protected void onResize(float width, float height) {
123 | super.onResize(width, height);
124 | updateRadialGradient((int) width);
125 | }
126 |
127 | @Override
128 | public void draw(Canvas canvas, Paint paint) {
129 | final int viewWidth = CircleImageView.this.getWidth();
130 | final int viewHeight = CircleImageView.this.getHeight();
131 | canvas.drawCircle(viewWidth / 2, viewHeight / 2, viewWidth / 2, mShadowPaint);
132 | canvas.drawCircle(viewWidth / 2, viewHeight / 2, viewWidth / 2 - mShadowRadius, paint);
133 | }
134 |
135 | private void updateRadialGradient(int diameter) {
136 | mRadialGradient = new RadialGradient(diameter / 2, diameter / 2,
137 | mShadowRadius, new int[] { FILL_SHADOW_COLOR, Color.TRANSPARENT },
138 | null, Shader.TileMode.CLAMP);
139 | mShadowPaint.setShader(mRadialGradient);
140 | }
141 | }
142 | }
143 |
--------------------------------------------------------------------------------
/Hugging Face/app/src/main/java/co/median/android/widget/HandleView.kt:
--------------------------------------------------------------------------------
1 | package co.median.android.widget
2 |
3 | import android.animation.ArgbEvaluator
4 | import android.animation.ValueAnimator
5 | import android.content.Context
6 | import android.graphics.Color
7 | import android.graphics.PorterDuff
8 | import android.graphics.drawable.Drawable
9 | import android.util.AttributeSet
10 | import android.widget.ImageView
11 | import android.widget.RelativeLayout
12 | import android.widget.TextView
13 | import androidx.annotation.ColorInt
14 | import androidx.core.content.res.ResourcesCompat
15 | import co.median.android.R
16 |
17 | class HandleView : RelativeLayout {
18 | private val iconView: ImageView
19 | private val textView: TextView
20 |
21 | init {
22 | inflate(context, R.layout.view_handle, this)
23 | iconView = findViewById(R.id.icon)
24 | textView = findViewById(R.id.text)
25 | }
26 |
27 | @JvmOverloads
28 | constructor(
29 | context: Context,
30 | attrs: AttributeSet? = null,
31 | defStyle: Int = 0
32 | ) : super(context, attrs, defStyle) {
33 | context.theme.obtainStyledAttributes(attrs, R.styleable.HandleView, 0, 0).apply {
34 | val backgroundDrawable = getDrawable(R.styleable.HandleView_handleBackground)
35 | ?: ResourcesCompat.getDrawable(
36 | resources,
37 | R.drawable.shape_rounded,
38 | context.theme
39 | )
40 | val iconDrawable = getDrawable(R.styleable.HandleView_iconDrawable)
41 | val text = getString(R.styleable.HandleView_text)
42 | val inactiveColor = getColor(R.styleable.HandleView_inactiveColor, inactiveColor)
43 | val activeColor = getColor(R.styleable.HandleView_activeColor, activeColor)
44 | initView(backgroundDrawable, iconDrawable, text, inactiveColor, activeColor)
45 | }
46 | }
47 |
48 | constructor(
49 | context: Context,
50 | backgroundDrawable: Drawable?,
51 | iconDrawable: Drawable?,
52 | text: String?,
53 | @ColorInt inactiveColor: Int,
54 | @ColorInt activeColor: Int,
55 | ) : super(context, null, 0) {
56 | initView(backgroundDrawable, iconDrawable, text, inactiveColor, activeColor)
57 | }
58 |
59 | var maxTextWidth: Int = Int.MIN_VALUE
60 | var inactiveColor: Int = Color.WHITE
61 | var activeColor: Int = Color.WHITE
62 |
63 | fun initView(
64 | backgroundDrawable: Drawable?,
65 | iconDrawable: Drawable?,
66 | text: String?,
67 | @ColorInt inactiveColor: Int,
68 | @ColorInt activeColor: Int
69 | ) {
70 | background = backgroundDrawable
71 | iconView.setImageDrawable(iconDrawable)
72 | setText(text)
73 | textView.layoutParams.let {
74 | it.width = 0
75 | textView.layoutParams = it
76 | }
77 |
78 | this.inactiveColor = inactiveColor
79 | this.activeColor = activeColor
80 | iconView.setColorFilter(inactiveColor)
81 | }
82 |
83 | fun setText(text: String?) {
84 | textView.layoutParams.width = LayoutParams.WRAP_CONTENT
85 | textView.text = text
86 | textView.measure(
87 | MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
88 | MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)
89 | )
90 | maxTextWidth = textView.measuredWidth
91 | textView.layoutParams.let {
92 | it.width = 0
93 | textView.layoutParams = it
94 | }
95 | }
96 |
97 | fun animateShowText() {
98 | if (textView.text.isEmpty()) {
99 | return
100 | }
101 | if (textView.layoutParams.width != 0) {
102 | textView.layoutParams.let {
103 | it.width = 0
104 | textView.layoutParams = it
105 | }
106 | }
107 | val animator = ValueAnimator.ofInt(0, maxTextWidth)
108 | animator.addUpdateListener { anim ->
109 | val value = anim.animatedValue as Int
110 | textView.layoutParams.let {
111 | it.width = value
112 | textView.layoutParams = it
113 | }
114 | }
115 | animator.duration = 300
116 | animator.start()
117 | }
118 |
119 | fun animateHideText() {
120 | if (textView.text.isEmpty()) {
121 | return
122 | }
123 | val animator = ValueAnimator.ofInt(maxTextWidth, 0)
124 | animator.duration = 300
125 | animator.addUpdateListener { anim ->
126 | val value = anim.animatedValue as Int
127 | val params = textView.layoutParams
128 | params.width = value
129 | textView.layoutParams = params
130 | }
131 | animator.start()
132 | }
133 |
134 | fun animateActive() {
135 | val animator = ValueAnimator.ofObject(ArgbEvaluator(), inactiveColor, activeColor)
136 | animator.addUpdateListener { anim ->
137 | val color = anim.animatedValue as Int
138 | textView.setTextColor(color)
139 | iconView.setColorFilter(color, PorterDuff.Mode.SRC_IN)
140 | }
141 | animator.duration = 100
142 | animator.start()
143 | }
144 |
145 | fun animateInactive() {
146 | val animator = ValueAnimator.ofObject(ArgbEvaluator(), activeColor, inactiveColor)
147 | animator.addUpdateListener { anim ->
148 | val color = anim.animatedValue as Int
149 | textView.setTextColor(color)
150 | iconView.setColorFilter(color, PorterDuff.Mode.SRC_IN)
151 | }
152 | animator.duration = 200
153 | animator.start()
154 | }
155 | }
--------------------------------------------------------------------------------
/Hugging Face/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # For Cygwin, ensure paths are in UNIX format before anything is touched.
46 | if $cygwin ; then
47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
48 | fi
49 |
50 | # Attempt to set APP_HOME
51 | # Resolve links: $0 may be a link
52 | PRG="$0"
53 | # Need this for relative symlinks.
54 | while [ -h "$PRG" ] ; do
55 | ls=`ls -ld "$PRG"`
56 | link=`expr "$ls" : '.*-> \(.*\)$'`
57 | if expr "$link" : '/.*' > /dev/null; then
58 | PRG="$link"
59 | else
60 | PRG=`dirname "$PRG"`"/$link"
61 | fi
62 | done
63 | SAVED="`pwd`"
64 | cd "`dirname \"$PRG\"`/" >&-
65 | APP_HOME="`pwd -P`"
66 | cd "$SAVED" >&-
67 |
68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
69 |
70 | # Determine the Java command to use to start the JVM.
71 | if [ -n "$JAVA_HOME" ] ; then
72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
73 | # IBM's JDK on AIX uses strange locations for the executables
74 | JAVACMD="$JAVA_HOME/jre/sh/java"
75 | else
76 | JAVACMD="$JAVA_HOME/bin/java"
77 | fi
78 | if [ ! -x "$JAVACMD" ] ; then
79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
80 |
81 | Please set the JAVA_HOME variable in your environment to match the
82 | location of your Java installation."
83 | fi
84 | else
85 | JAVACMD="java"
86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
87 |
88 | Please set the JAVA_HOME variable in your environment to match the
89 | location of your Java installation."
90 | fi
91 |
92 | # Increase the maximum file descriptors if we can.
93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
94 | MAX_FD_LIMIT=`ulimit -H -n`
95 | if [ $? -eq 0 ] ; then
96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
97 | MAX_FD="$MAX_FD_LIMIT"
98 | fi
99 | ulimit -n $MAX_FD
100 | if [ $? -ne 0 ] ; then
101 | warn "Could not set maximum file descriptor limit: $MAX_FD"
102 | fi
103 | else
104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
105 | fi
106 | fi
107 |
108 | # For Darwin, add options to specify how the application appears in the dock
109 | if $darwin; then
110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
111 | fi
112 |
113 | # For Cygwin, switch paths to Windows format before running java
114 | if $cygwin ; then
115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
158 | function splitJvmOpts() {
159 | JVM_OPTS=("$@")
160 | }
161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
163 |
164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
165 |
--------------------------------------------------------------------------------
/Hugging Face/plugins.gradle:
--------------------------------------------------------------------------------
1 | import groovy.json.JsonSlurper
2 | import org.gradle.initialization.DefaultSettings
3 | import org.apache.tools.ant.taskdefs.condition.Os
4 |
5 | def generatedFileName = "PackageList.java"
6 | def generatedFilePackage = "co.median.android"
7 | def generatedFileContentsTemplate = """
8 | package $generatedFilePackage;
9 |
10 | import android.app.Application;
11 | import android.content.Context;
12 | import android.content.res.Resources;
13 |
14 | import co.median.median_core.BridgeModule;
15 | import java.util.Arrays;
16 | import java.util.ArrayList;
17 |
18 | {{ packageImports }}
19 |
20 | public class PackageList {
21 | private Application application;
22 |
23 | public PackageList(Application application) {
24 | this.application = application;
25 | }
26 |
27 | private Resources getResources() {
28 | return this.getApplication().getResources();
29 | }
30 |
31 | private Application getApplication() {
32 | return this.application;
33 | }
34 |
35 | private Context getApplicationContext() {
36 | return this.getApplication().getApplicationContext();
37 | }
38 |
39 | public ArrayList getPackages() {
40 | return new ArrayList<>(Arrays.asList(
41 | {{ packageClassInstances }}
42 | ));
43 | }
44 | }
45 | """
46 |
47 | class GoNativeModules {
48 | private Logger logger
49 | private ArrayList> modulesMetadata
50 |
51 | private packageName = "co.median.android"
52 |
53 | GoNativeModules(Logger logger) {
54 | this.logger = logger
55 | this.modulesMetadata = this.getModulesMetadata()
56 | }
57 |
58 | ArrayList> getModulesMetadata() {
59 | if (this.modulesMetadata != null) return this.modulesMetadata
60 |
61 | ArrayList> modulesMetadata = new ArrayList>()
62 |
63 | def finder = new FileNameFinder()
64 | def files = finder.getFileNames(System.getProperty("user.dir"), 'plugins/**/plugin-metadata.json')
65 | files.each { fileName ->
66 | def jsonFile = new File(fileName)
67 | def parsedJson = new JsonSlurper().parseText(jsonFile.text).plugin
68 | parsedJson["sourceDir"] = fileName.tokenize(File.separator)[-3..-2].join(File.separator)
69 | modulesMetadata.push(parsedJson)
70 | }
71 |
72 | return modulesMetadata
73 | }
74 |
75 | void addModuleProjects(DefaultSettings defaultSettings) {
76 | modulesMetadata.forEach { module ->
77 | String pluginName = module["pluginName"]
78 | String sourceDir = module["sourceDir"]
79 | this.logger.warn(sourceDir)
80 | defaultSettings.include(":${pluginName}")
81 | defaultSettings.project(":${pluginName}").projectDir = new File(defaultSettings.rootProject.projectDir, "./${sourceDir}")
82 |
83 | // Include local library required by the plugin
84 | String localLibrary = module["localLibrary"]
85 | if (localLibrary != null && !localLibrary.isEmpty()) {
86 | defaultSettings.include(":${localLibrary}")
87 | defaultSettings.project(":${localLibrary}").projectDir = new File(defaultSettings.rootProject.projectDir, "./${sourceDir}/${localLibrary}")
88 | }
89 | }
90 | }
91 |
92 | void addModuleDependencies(Project appProject) {
93 | modulesMetadata.forEach { module ->
94 | String pluginName = module["pluginName"]
95 | appProject.dependencies {
96 | implementation project(path: ":${pluginName}")
97 | }
98 | }
99 | }
100 |
101 | void generatePackagesFile(File outputDir, String generatedFileName, GString generatedFileContentsTemplate) {
102 | def packages = this.modulesMetadata
103 | String packageName = this.packageName
104 |
105 | String packageImports = ""
106 | String packageClassInstances = ""
107 |
108 | if (packages.size() > 0) {
109 | packageImports = "import ${packageName}.BuildConfig;\nimport ${packageName}.R;\n\n"
110 | packageImports = packageImports + packages.collect {
111 | "// ${it.name}\nimport ${it.packageName}.${it.classInstance};"
112 | }.join('\n')
113 | packageClassInstances = packages.collect { "new ${it.classInstance}()" }.join(",\n ")
114 | }
115 |
116 | String generatedFileContents = generatedFileContentsTemplate.toString()
117 | .replace("{{ packageImports }}", packageImports)
118 | .replace("{{ packageClassInstances }}", packageClassInstances)
119 |
120 | outputDir.mkdirs()
121 | final FileTreeBuilder treeBuilder = new FileTreeBuilder(outputDir)
122 | treeBuilder.file(generatedFileName).newWriter().withWriter { w ->
123 | w << generatedFileContents
124 | }
125 | }
126 | }
127 |
128 | def gonativeModules = new GoNativeModules(logger)
129 |
130 | ext.applyModulesSettingsGradle = { DefaultSettings defaultSettings ->
131 | gonativeModules.addModuleProjects(defaultSettings)
132 | }
133 |
134 | ext.applyNativeModulesAppBuildGradle = { Project project ->
135 | gonativeModules.addModuleDependencies(project)
136 |
137 | def generatedSrcDir = new File(buildDir, "generated/gncli/src/main/java")
138 | def generatedCodeDir = new File(generatedSrcDir, generatedFilePackage.replace('.', '/'))
139 |
140 | task generatePackageList {
141 | doLast {
142 | gonativeModules.generatePackagesFile(generatedCodeDir, generatedFileName, generatedFileContentsTemplate)
143 | }
144 | }
145 |
146 | preBuild.dependsOn generatePackageList
147 |
148 | android {
149 | sourceSets {
150 | main {
151 | java {
152 | srcDirs += generatedSrcDir
153 | }
154 | }
155 | }
156 | }
157 | }
--------------------------------------------------------------------------------
/Hugging Face/app/src/main/java/co/median/android/Installation.java:
--------------------------------------------------------------------------------
1 | package co.median.android;
2 |
3 | import android.content.Context;
4 | import android.content.pm.ApplicationInfo;
5 | import android.content.pm.PackageInfo;
6 | import android.content.pm.PackageManager;
7 | import android.os.Build;
8 | import android.telephony.SubscriptionInfo;
9 | import android.telephony.SubscriptionManager;
10 | import android.util.Log;
11 |
12 | import androidx.core.app.ActivityCompat;
13 |
14 | import java.io.File;
15 | import java.io.FileOutputStream;
16 | import java.io.IOException;
17 | import java.io.RandomAccessFile;
18 | import java.util.ArrayList;
19 | import java.util.HashMap;
20 | import java.util.List;
21 | import java.util.Locale;
22 | import java.util.Map;
23 | import java.util.TimeZone;
24 | import java.util.UUID;
25 |
26 | import co.median.median_core.AppConfig;
27 | import co.median.median_core.GNLog;
28 |
29 | /**
30 | * Created by weiyin on 8/8/14.
31 | */
32 | public class Installation {
33 | private static final String TAG = Installation.class.getName();
34 |
35 | private static String sID = null;
36 | private static final String INSTALLATION = "INSTALLATION";
37 |
38 | public synchronized static String id(Context context) {
39 | if (sID == null) {
40 | File installation = new File(context.getFilesDir(), INSTALLATION);
41 | try {
42 | if (!installation.exists())
43 | writeInstallationFile(installation);
44 | sID = readInstallationFile(installation);
45 | } catch (Exception e) {
46 | throw new RuntimeException(e);
47 | }
48 | }
49 | return sID;
50 | }
51 |
52 | public static Map getInfo(Context context) {
53 | HashMap info = new HashMap<>();
54 |
55 | info.put("platform", "android");
56 |
57 | String publicKey = AppConfig.getInstance(context).publicKey;
58 | if (publicKey == null) publicKey = "";
59 | info.put("publicKey", publicKey);
60 |
61 | String packageName = context.getPackageName();
62 | info.put("appId", packageName);
63 |
64 |
65 | PackageManager manager = context.getPackageManager();
66 | try {
67 | PackageInfo packageInfo = manager.getPackageInfo(packageName, 0);
68 | info.put("appVersion", packageInfo.versionName);
69 | info.put("appVersionCode", packageInfo.versionCode);
70 | } catch (PackageManager.NameNotFoundException e) {
71 | GNLog.getInstance().logError(TAG, e.getMessage(), e);
72 | }
73 |
74 | String distribution;
75 | boolean isDebuggable = ( 0 != ( context.getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE ) );
76 | if (isDebuggable) {
77 | distribution = "debug";
78 | } else {
79 | String installer = manager.getInstallerPackageName(packageName);
80 | if (installer == null) {
81 | distribution = "adhoc";
82 | } else if (installer.equals("com.android.vending") || installer.equals("com.google.market")) {
83 | distribution = "playstore";
84 | } else if (installer.equals("com.amazon.venezia")) {
85 | distribution = "amazon";
86 | } else {
87 | distribution = installer;
88 | }
89 | }
90 | info.put("distribution", distribution);
91 |
92 | info.put("language", Locale.getDefault().getLanguage());
93 | info.put("os", "Android");
94 | info.put("osVersion", Build.VERSION.RELEASE);
95 | info.put("model", Build.MANUFACTURER + " " + Build.MODEL);
96 | info.put("hardware", Build.FINGERPRINT);
97 | info.put("timeZone", TimeZone.getDefault().getID());
98 | info.put("deviceName", getDeviceName());
99 |
100 | if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP_MR1) {
101 | SubscriptionManager subscriptionManager = SubscriptionManager.from(context);
102 |
103 | if (ActivityCompat.checkSelfPermission(context, android.Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED) {
104 | List carriers = new ArrayList<>();
105 | for (SubscriptionInfo subscriptionInfo : subscriptionManager.getActiveSubscriptionInfoList()) {
106 | carriers.add(subscriptionInfo.getCarrierName().toString());
107 | }
108 | info.put("carrierNames", carriers);
109 | try {
110 | info.put("carrierName", carriers.get(0));
111 | } catch ( IndexOutOfBoundsException e ) {
112 | Log.w(TAG, "getInfo: No carriers registered with subscription manager");
113 | }
114 | } else {
115 | Log.w(TAG, "getInfo: Cannot get carrierNames, READ_PHONE_STATE not granted");
116 | }
117 | }
118 |
119 | info.put("installationId", Installation.id(context));
120 |
121 | return info;
122 | }
123 |
124 | private static String readInstallationFile(File installation) throws IOException {
125 | RandomAccessFile f = new RandomAccessFile(installation, "r");
126 | byte[] bytes = new byte[(int) f.length()];
127 | f.readFully(bytes);
128 | f.close();
129 | return new String(bytes);
130 | }
131 |
132 | private static void writeInstallationFile(File installation) throws IOException {
133 | FileOutputStream out = new FileOutputStream(installation);
134 | String id = UUID.randomUUID().toString();
135 | out.write(id.getBytes());
136 | out.close();
137 | }
138 |
139 | private static String getDeviceName() {
140 | String manufacturer = Build.MANUFACTURER;
141 | String model = Build.MODEL;
142 | String name;
143 | if (model.startsWith(manufacturer)) {
144 | name = model;
145 | } else {
146 | name = manufacturer + " " + model;
147 | }
148 | return name;
149 | }
150 | }
--------------------------------------------------------------------------------