├── .gitignore ├── .travis.yml ├── LICENSE ├── NOTICE ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── info │ │ └── schnatterer │ │ └── pmcaFilesystemServer │ │ ├── BaseActivity.java │ │ ├── FilesystemScanner.java │ │ ├── HttpServer.java │ │ ├── ListAdapter.java │ │ ├── Logger.java │ │ ├── MainActivity.java │ │ ├── WifiActivity.java │ │ ├── WifiDirectActivity.java │ │ └── WifiSettingActivity.java │ └── res │ ├── layout │ ├── list.xml │ └── log.xml │ ├── mipmap-hdpi │ └── ic_launcher.png │ ├── mipmap-mdpi │ └── ic_launcher.png │ ├── mipmap-xhdpi │ └── ic_launcher.png │ ├── mipmap-xxhdpi │ └── ic_launcher.png │ ├── mipmap-xxxhdpi │ └── ic_launcher.png │ ├── values │ └── strings.xml │ └── web_hi_res_512.png ├── build.gradle ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | /.gradle 2 | /.idea 3 | /build 4 | /local.properties 5 | /*.iml 6 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: android 2 | 3 | env: 4 | - BUILD_TOOLS_VERSION=28.0.3 5 | 6 | android: 7 | components: 8 | # Use the latest revision of Android SDK Tools 9 | - tools 10 | - platform-tools 11 | 12 | # When changing the following, change also in build.gradle! 13 | - build-tools-${BUILD_TOOLS_VERSION} 14 | - android-23 15 | 16 | - extra-android-m2repository 17 | 18 | before_install: 19 | # Avoid ./gradlew: Permission denied 20 | - chmod +x gradlew 21 | 22 | install: 23 | # Avoids "Failed to install the following Android SDK packages as some licences have not been accepted." 24 | - echo yes | sdkmanager "build-tools;${BUILD_TOOLS_VERSION}" 25 | 26 | cache: 27 | directories: 28 | - $HOME/.gradle/caches/ 29 | - $HOME/.gradle/wrapper/ 30 | 31 | script: 32 | # Use assembleRelease here to make sure the changes have not affected proguard 33 | - ./gradlew clean build connectedCheck assembleRelease --stacktrace 34 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2019 Johannes Schnatterer 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | pmcaFilesystemServer 2 | 3 | Copyright 2019 Johannes Schnatterer. 4 | Published under The MIT License (MIT). 5 | 6 | This product reuses code of the following products. 7 | 8 | * https://github.com/ma1co/PMCADemo 9 | * https://github.com/LubikR/SynologyUploader 10 | * https://github.com/Bostwickenator/STGUploader 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | pmcaFilesystemServer 2 | ==== 3 | [![Build Status](https://travis-ci.org/schnatterer/pmcaFilesystemServer.svg?branch=develop)](https://travis-ci.org/schnatterer/pmcaFilesystemServer) 4 | 5 | Simple Android app for Sony Cameras ( PlayMemories Camera App Store) that provides the File System 6 | of the camera via HTTP. 7 | 8 | This app uses the [OpenMemories: Framework](https://github.com/ma1co/OpenMemories-Framework) and is 9 | greatly inspired by the following existing open source PMCA Apps 10 | 11 | * [ma1co/PMCADemo](https://github.com/ma1co/PMCADemo) 12 | * [LubikR/SynologyUploader](https://github.com/LubikR/SynologyUploader) 13 | * [Bostwickenator/STGUploader](https://github.com/Bostwickenator/STGUploader) 14 | 15 | # Pre-release of new UI 16 | 17 | The PR for the new user interface hase been dangling for years. Now there is a pre-release that can be installed via Sony-PMCA-RE or through adb. See [#4](https://github.com/schnatterer/pmcaFilesystemServer/pull/4). 18 | 19 |      20 | 21 | # Installation 22 | 23 | * Use [Sony-PMCA-RE](https://github.com/ma1co/Sony-PMCA-RE), 24 | * via [sony-pmca.appspot.com](https://sony-pmca.appspot.com/apps) or 25 | * through adb (using [tweak app](https://github.com/ma1co/OpenMemories-Tweak)). 26 | 27 | # Usage 28 | 29 | On Startup a WiFi Connection will be established. Once this succeeds a webserver is started 30 | and its URL is displayed. There you can download all data from the camera, like images and videos. 31 | 32 | This works around the constraint of certain Sony cameras where videos can not be downloaded via WiFi. 33 | 34 | The Web Server exposes the whole file system without authentication to everyone on the same network 35 | as the camera. Make sure to run this in a private network, using WiFi direct or by using your 36 | Mobile's Hotspot. 37 | 38 | # Development 39 | 40 | ```bash 41 | adb tcpip 5555 42 | adb connect 192.168.178.53:5555 43 | ``` 44 | 45 | See https://stackoverflow.com/a/3623727 46 | 47 | For creating a release, set git tag and then upload an *unsigned* APK to GitHub's release page. 48 | Signed APKs seem to be denied by Sony-PMCA-RE. 49 | 50 | The app writes a log file to the SD card: `/storage/sdcard0/pmcaFilesystemServer/LOG.TXT`. 51 | 52 | ## Icon 53 | 54 | Was generated with 55 | [AndroidAssetStudio](https://romannurik.github.io/AndroidAssetStudio/icons-launcher.html#foreground.type=text&foreground.text.text=HTTP%20FS&foreground.text.font=Allerta%20Stencil&foreground.space.trim=1&foreground.space.pad=0.1&foreColor=rgba(96%2C%20125%2C%20139%2C%200)&backColor=rgb(139%2C%20195%2C%2074)&crop=0&backgroundShape=square&effects=none&name=ic_launcher) 56 | 57 | ## Feature Ideas 58 | 59 | * QR Code: https://stackoverflow.com/a/8800974/ 60 | * Basic Auth: https://github.com/NanoHttpd/nanohttpd/issues/496 61 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | /*.iml 3 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | /* Cameras run older android systems, e.g. 5 | Sony α 6500: 6 | adb shell getprop ro.build.version.release 7 | 4.1.2 8 | adb shell getprop ro.build.version.sdk 9 | 16 10 | */ 11 | compileSdkVersion 23 12 | buildToolsVersion '28.0.3' 13 | 14 | defaultConfig { 15 | applicationId "info.schnatterer.pmcaFilesystemServer" 16 | //noinspection MinSdkTooLow 17 | minSdkVersion 10 18 | //noinspection ExpiredTargetSdkVersion 19 | targetSdkVersion 23 20 | versionCode 2 21 | versionName "0.1.1-SNAPSHOT" 22 | } 23 | buildTypes { 24 | release { 25 | minifyEnabled false 26 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 27 | } 28 | } 29 | } 30 | 31 | dependencies { 32 | compile 'com.github.ma1co.OpenMemories-Framework:framework:f8df350' 33 | provided 'com.github.ma1co.OpenMemories-Framework:stubs:f8df350' 34 | compile 'org.nanohttpd:nanohttpd-webserver:2.3.1' 35 | } -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in C:\Users\Alex\AppData\Local\Android\sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | # Needed to keep generic types and @Key annotations accessed via reflection 19 | -keepattributes Signature,RuntimeVisibleAnnotations,AnnotationDefault 20 | 21 | -keepclasseswithmembers class * { 22 | @com.google.api.client.util.Key ; 23 | } 24 | 25 | -keepclasseswithmembers class * { 26 | @com.google.api.client.util.Value ; 27 | } 28 | 29 | -keepnames class com.google.api.client.http.HttpTransport 30 | 31 | # Needed by google-http-client-android when linking against an older platform version 32 | -dontwarn com.google.api.client.extensions.android.** 33 | 34 | # Needed by google-api-client-android when linking against an older platform version 35 | -dontwarn com.google.api.client.googleapis.extensions.android.** 36 | 37 | # Do not obfuscate but allow shrinking of android-oauth-client 38 | -keepnames class com.wuman.android.auth.** { *; } -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 27 | 28 | 31 | 32 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /app/src/main/java/info/schnatterer/pmcaFilesystemServer/BaseActivity.java: -------------------------------------------------------------------------------- 1 | package info.schnatterer.pmcaFilesystemServer; 2 | 3 | import android.app.Activity; 4 | import android.content.Intent; 5 | import android.view.KeyEvent; 6 | 7 | import com.sony.scalar.sysutil.ScalarInput; 8 | 9 | public class BaseActivity extends Activity { 10 | 11 | @Override 12 | public boolean onKeyDown(int keyCode, KeyEvent event) { 13 | switch (event.getScanCode()) { 14 | case ScalarInput.ISV_KEY_DELETE: 15 | case ScalarInput.ISV_KEY_SK2: 16 | case ScalarInput.ISV_KEY_MENU: 17 | return onDeleteKeyUp(); 18 | default: 19 | return super.onKeyDown(keyCode, event); 20 | } 21 | } 22 | 23 | protected boolean onDeleteKeyUp() { 24 | onBackPressed(); 25 | return true; 26 | } 27 | 28 | protected void setAutoPowerOffMode(boolean enable) { 29 | String mode = enable ? "APO/NORMAL" : "APO/NO";// or "APO/SPECIAL" ? 30 | Intent intent = new Intent(); 31 | intent.setAction("com.android.server.DAConnectionManagerService.apo"); 32 | intent.putExtra("apo_info", mode); 33 | sendBroadcast(intent); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /app/src/main/java/info/schnatterer/pmcaFilesystemServer/FilesystemScanner.java: -------------------------------------------------------------------------------- 1 | package info.schnatterer.pmcaFilesystemServer; 2 | 3 | import android.os.Environment; 4 | 5 | import java.io.File; 6 | import java.util.ArrayList; 7 | import java.util.Iterator; 8 | import java.util.List; 9 | 10 | /* 11 | * Bases on https://github.com/Bostwickenator/STGUploader/blob/master/app/src/main/java/org/bostwickenator/googlephotos/FilesystemScanner.java 12 | * Commit b8ce40d 13 | */ 14 | class FilesystemScanner { 15 | 16 | private static final String[] rawFormats = {".arw"}; 17 | private static final String[] jpegFormats = {".jpg"}; 18 | private static final String[] videoFormats = {".mts", ".mp4"}; 19 | 20 | public static List getRawsOnExternalStorage() { 21 | return getFilteredFileList(Environment.getExternalStorageDirectory(), rawFormats); 22 | } 23 | 24 | public static List getJpegsOnExternalStorage() { 25 | return getFilteredFileList(Environment.getExternalStorageDirectory(), jpegFormats); 26 | } 27 | 28 | public static List getVideosOnExternalStorage() { 29 | return getFilteredFileList(Environment.getExternalStorageDirectory(), videoFormats); 30 | } 31 | 32 | private static List getFilteredFileList(File directory, String... extensions) { 33 | File[] subFiles = directory.listFiles(); 34 | List filtered = new ArrayList<>(); 35 | if (subFiles != null) { 36 | for (File f : subFiles) { 37 | String filename = f.getName().toLowerCase(); 38 | if (f.isFile()) { 39 | for (String extension : extensions) { 40 | if (filename.endsWith(extension)) { 41 | filtered.add(f); 42 | break; 43 | } 44 | } 45 | } else if (f.isDirectory()) { 46 | filtered.addAll(getFilteredFileList(f, extensions)); 47 | } 48 | } 49 | } 50 | return filtered; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /app/src/main/java/info/schnatterer/pmcaFilesystemServer/HttpServer.java: -------------------------------------------------------------------------------- 1 | package info.schnatterer.pmcaFilesystemServer; 2 | 3 | import com.github.ma1co.openmemories.framework.DeviceInfo; 4 | 5 | import java.io.File; 6 | import java.util.List; 7 | 8 | import fi.iki.elonen.SimpleWebServer; 9 | 10 | public class HttpServer extends SimpleWebServer { 11 | static final int PORT = 8080; 12 | static final String HOST = null; // bind to all interfaces by default 13 | static final String WWW_ROOT = "/"; 14 | static final boolean QUIET = false; 15 | 16 | public HttpServer() { 17 | super(HOST, PORT, new File(WWW_ROOT).getAbsoluteFile(), QUIET); 18 | } 19 | 20 | @Override 21 | public Response serve(IHTTPSession session) { 22 | 23 | if (session.getUri().equals("/")) { 24 | return serveRoot(); 25 | } else { 26 | return super.serve(session); 27 | } 28 | } 29 | 30 | private Response serveRoot() { 31 | String heading = getDeviceInfo().getBrand() + " - " + getDeviceInfo().getModel(); 32 | StringBuilder response = new StringBuilder("" + heading 33 | + "" + "

" + heading + "

"); 36 | 37 | response.append("

Videos

"); 38 | createFileList(FilesystemScanner.getVideosOnExternalStorage(), response); 39 | 40 | response.append("

JPEGs

"); 41 | createFileList(FilesystemScanner.getJpegsOnExternalStorage(), response); 42 | 43 | response.append("

RAW

"); 44 | createFileList(FilesystemScanner.getRawsOnExternalStorage(), response); 45 | 46 | response.append("

Log File

"); 47 | createLinkToLogFile(response); 48 | 49 | response.append("

File System

"); 50 | response.append(listDirectory("/", new File("/")) 51 | .replaceFirst(".*", "")); 52 | return newFixedLengthResponse(Response.Status.OK, MIME_HTML, response.toString()); 53 | } 54 | 55 | private void createLinkToLogFile(StringBuilder response) { 56 | response.append(""); 60 | response.append(logFile.getName()); 61 | response.append(""); 62 | } 63 | 64 | private DeviceInfo getDeviceInfo() { 65 | return DeviceInfo.getInstance(); 66 | } 67 | 68 | private void createFileList(List files, StringBuilder response) { 69 | response.append(""); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /app/src/main/java/info/schnatterer/pmcaFilesystemServer/ListAdapter.java: -------------------------------------------------------------------------------- 1 | package info.schnatterer.pmcaFilesystemServer; 2 | 3 | import android.content.Context; 4 | import android.view.LayoutInflater; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | import android.widget.ArrayAdapter; 8 | import android.widget.TextView; 9 | 10 | public class ListAdapter extends ArrayAdapter { 11 | public static class ListItem { 12 | public String getText1() { return ""; } 13 | public String getText2() { return ""; } 14 | } 15 | 16 | public ListAdapter(Context context, T[] objects) { 17 | super(context, 0, objects); 18 | } 19 | 20 | @Override 21 | public View getView(int position, View convertView, ViewGroup parent) { 22 | LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); 23 | if (convertView == null) 24 | convertView = inflater.inflate(android.R.layout.simple_list_item_2, parent, false); 25 | T item = getItem(position); 26 | ((TextView) convertView.findViewById(android.R.id.text1)).setText(item.getText1()); 27 | ((TextView) convertView.findViewById(android.R.id.text2)).setText(item.getText2()); 28 | return convertView; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /app/src/main/java/info/schnatterer/pmcaFilesystemServer/Logger.java: -------------------------------------------------------------------------------- 1 | package info.schnatterer.pmcaFilesystemServer; 2 | 3 | import android.os.Environment; 4 | import android.util.Log; 5 | 6 | import java.io.*; 7 | import java.text.SimpleDateFormat; 8 | import java.util.Date; 9 | import java.util.Locale; 10 | 11 | public class Logger { 12 | 13 | public static final String DATE_PATTERN = "yyyy-MM-dd'T'HH:mm:ss.SSS"; 14 | 15 | public static File getFile() { 16 | // e.g. /storage/sdcard0/pmcaFilesystemServer/LOG.TXT 17 | return new File(Environment.getExternalStorageDirectory(), "pmcaFilesystemServer/LOG.TXT"); 18 | } 19 | 20 | protected static void log(String msg) { 21 | try { 22 | getFile().getParentFile().mkdirs(); 23 | BufferedWriter writer = new BufferedWriter(new FileWriter(getFile(), true)); 24 | SimpleDateFormat sdf = new SimpleDateFormat(DATE_PATTERN, Locale.US); 25 | writer.append(sdf.format(new Date())); 26 | writer.append(" "); 27 | writer.append(msg); 28 | writer.newLine(); 29 | writer.close(); 30 | } catch (IOException e) { 31 | Log.e("pmcaFilesystemServer", "Error writing log", e); 32 | } 33 | } 34 | protected static void log(String type, String msg) { log("[" + type + "] " + msg); } 35 | 36 | public static void info(String msg) { log("INFO", msg); } 37 | public static void error(String msg) { log("ERROR", msg); } 38 | } 39 | -------------------------------------------------------------------------------- /app/src/main/java/info/schnatterer/pmcaFilesystemServer/MainActivity.java: -------------------------------------------------------------------------------- 1 | package info.schnatterer.pmcaFilesystemServer; 2 | 3 | import android.app.Activity; 4 | import android.content.Intent; 5 | import android.os.Bundle; 6 | import android.view.View; 7 | import android.widget.AdapterView; 8 | import android.widget.ListView; 9 | 10 | import java.io.PrintWriter; 11 | import java.io.StringWriter; 12 | 13 | public class MainActivity extends BaseActivity implements AdapterView.OnItemClickListener { 14 | protected class ActivityListItem extends ListAdapter.ListItem { 15 | private int nameResource; 16 | private Class clazz; 17 | 18 | public ActivityListItem(int nameResource, Class clazz) { 19 | this.nameResource = nameResource; 20 | this.clazz = clazz; 21 | } 22 | 23 | @Override 24 | public String getText1() { 25 | return getResources().getString(nameResource); 26 | } 27 | 28 | public Class getActivityClass() { 29 | return clazz; 30 | } 31 | } 32 | 33 | protected ActivityListItem activities[] = { 34 | new ActivityListItem(R.string.title_activity_wifi, WifiActivity.class), 35 | new ActivityListItem(R.string.title_activity_wifi_direct, WifiDirectActivity.class), 36 | new ActivityListItem(R.string.title_activity_wifi_setting, WifiSettingActivity.class), 37 | }; 38 | 39 | @Override 40 | protected void onCreate(Bundle savedInstanceState) { 41 | super.onCreate(savedInstanceState); 42 | setContentView(R.layout.list); 43 | 44 | Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() { 45 | @Override 46 | public void uncaughtException(Thread thread, Throwable throwable) { 47 | StringWriter sw = new StringWriter(); 48 | sw.append(throwable.toString()); 49 | sw.append("\n"); 50 | throwable.printStackTrace(new PrintWriter(sw)); 51 | Logger.error(sw.toString()); 52 | 53 | System.exit(0); 54 | } 55 | }); 56 | 57 | ListView listView = (ListView) findViewById(R.id.listView); 58 | listView.setAdapter(new ListAdapter(this, activities)); 59 | listView.setOnItemClickListener(this); 60 | } 61 | 62 | @Override 63 | public void onItemClick(AdapterView adapterView, View view, int position, long id) { 64 | ActivityListItem item = (ActivityListItem) adapterView.getItemAtPosition(position); 65 | startActivity(new Intent(this, item.getActivityClass())); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /app/src/main/java/info/schnatterer/pmcaFilesystemServer/WifiActivity.java: -------------------------------------------------------------------------------- 1 | package info.schnatterer.pmcaFilesystemServer; 2 | 3 | import android.content.BroadcastReceiver; 4 | import android.content.Context; 5 | import android.content.Intent; 6 | import android.content.IntentFilter; 7 | import android.net.NetworkInfo; 8 | import android.net.wifi.SupplicantState; 9 | import android.net.wifi.WifiInfo; 10 | import android.net.wifi.WifiManager; 11 | import android.os.Bundle; 12 | import android.text.format.Formatter; 13 | import android.widget.TextView; 14 | 15 | import java.io.IOException; 16 | 17 | public class WifiActivity extends BaseActivity { 18 | private TextView textView; 19 | private WifiManager wifiManager; 20 | private BroadcastReceiver wifiStateReceiver; 21 | private BroadcastReceiver supplicantStateReceiver; 22 | private BroadcastReceiver networkStateReceiver; 23 | private HttpServer httpServer; 24 | 25 | @Override 26 | protected void onCreate(Bundle savedInstanceState) { 27 | super.onCreate(savedInstanceState); 28 | setContentView(R.layout.log); 29 | 30 | textView = (TextView) findViewById(R.id.logView); 31 | 32 | wifiManager = (WifiManager) getApplicationContext().getSystemService(WIFI_SERVICE); 33 | 34 | wifiStateReceiver = new BroadcastReceiver() { 35 | @Override 36 | public void onReceive(Context context, Intent intent) { 37 | wifiStateChanged(intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, WifiManager.WIFI_STATE_UNKNOWN)); 38 | } 39 | }; 40 | 41 | supplicantStateReceiver = new BroadcastReceiver() { 42 | @Override 43 | public void onReceive(Context context, Intent intent) { 44 | networkStateChanged(WifiInfo.getDetailedStateOf((SupplicantState) intent.getParcelableExtra(WifiManager.EXTRA_NEW_STATE))); 45 | } 46 | }; 47 | 48 | networkStateReceiver = new BroadcastReceiver() { 49 | @Override 50 | public void onReceive(Context context, Intent intent) { 51 | networkStateChanged(((NetworkInfo) intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO)).getDetailedState()); 52 | } 53 | }; 54 | 55 | httpServer = new HttpServer(); 56 | } 57 | 58 | @Override 59 | protected void onResume() { 60 | super.onResume(); 61 | registerReceiver(wifiStateReceiver, new IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION)); 62 | registerReceiver(supplicantStateReceiver, new IntentFilter(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION)); 63 | registerReceiver(networkStateReceiver, new IntentFilter(WifiManager.NETWORK_STATE_CHANGED_ACTION)); 64 | wifiManager.setWifiEnabled(true); 65 | try { 66 | httpServer.start(); 67 | } catch (IOException e) { 68 | Logger.error("Failed to start HTTP Server: " + e.getMessage()); 69 | } 70 | setAutoPowerOffMode(false); 71 | } 72 | 73 | @Override 74 | protected void onPause() { 75 | super.onPause(); 76 | unregisterReceiver(wifiStateReceiver); 77 | unregisterReceiver(supplicantStateReceiver); 78 | unregisterReceiver(networkStateReceiver); 79 | wifiManager.setWifiEnabled(false); 80 | httpServer.stop(); 81 | setAutoPowerOffMode(true); 82 | } 83 | 84 | @Override 85 | protected void onDestroy() { 86 | super.onDestroy(); 87 | } 88 | 89 | protected void wifiStateChanged(int state) { 90 | switch (state) { 91 | case WifiManager.WIFI_STATE_ENABLING: 92 | log("Enabling wifi"); 93 | break; 94 | case WifiManager.WIFI_STATE_ENABLED: 95 | log("Wifi enabled"); 96 | break; 97 | } 98 | } 99 | 100 | protected void networkStateChanged(NetworkInfo.DetailedState state) { 101 | String ssid = wifiManager.getConnectionInfo().getSSID(); 102 | switch (state) { 103 | case CONNECTING: 104 | if (ssid != null) 105 | log(ssid + ": Connecting"); 106 | break; 107 | case AUTHENTICATING: 108 | log(ssid + ": Authenticating"); 109 | break; 110 | case OBTAINING_IPADDR: 111 | log(ssid + ": Obtaining IP"); 112 | break; 113 | case CONNECTED: 114 | wifiConnected(); 115 | break; 116 | case DISCONNECTED: 117 | log("Disconnected"); 118 | break; 119 | case FAILED: 120 | log("Connection failed"); 121 | break; 122 | } 123 | } 124 | 125 | protected void wifiConnected() { 126 | WifiInfo info = wifiManager.getConnectionInfo(); 127 | String ssid = info.getSSID(); 128 | String ip = Formatter.formatIpAddress(info.getIpAddress()); 129 | log(ssid + ": Connected. Server URL: http://" + ip + ":" + HttpServer.PORT + "/"); 130 | } 131 | 132 | protected void log(String msg) { 133 | textView.setText(msg); 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /app/src/main/java/info/schnatterer/pmcaFilesystemServer/WifiDirectActivity.java: -------------------------------------------------------------------------------- 1 | package info.schnatterer.pmcaFilesystemServer; 2 | 3 | import android.annotation.SuppressLint; 4 | import android.content.BroadcastReceiver; 5 | import android.content.Context; 6 | import android.content.Intent; 7 | import android.content.IntentFilter; 8 | import android.net.wifi.WifiManager; 9 | import android.os.Bundle; 10 | import android.widget.TextView; 11 | 12 | import com.sony.wifi.direct.DirectConfiguration; 13 | import com.sony.wifi.direct.DirectManager; 14 | 15 | import java.io.IOException; 16 | import java.util.List; 17 | 18 | public class WifiDirectActivity extends BaseActivity { 19 | public static final String MY_IP_ADDRESS = "192.168.122.1"; 20 | 21 | private TextView textView; 22 | private WifiManager wifiManager; 23 | private DirectManager wifiDirectManager; 24 | private BroadcastReceiver wifiStateReceiver; 25 | private BroadcastReceiver wifiDirectStateReceiver; 26 | private BroadcastReceiver groupCreateSuccessReceiver; 27 | private BroadcastReceiver groupCreateFailureReceiver; 28 | private BroadcastReceiver stationConnectedReceiver; 29 | private BroadcastReceiver stationDisconnectedReceiver; 30 | private HttpServer httpServer; 31 | 32 | @Override 33 | // This seems to be a sony-specific value 34 | @SuppressLint("WrongConstant") 35 | protected void onCreate(Bundle savedInstanceState) { 36 | super.onCreate(savedInstanceState); 37 | setContentView(R.layout.log); 38 | 39 | textView = (TextView) findViewById(R.id.logView); 40 | 41 | wifiManager = (WifiManager) getApplicationContext().getSystemService(WIFI_SERVICE); 42 | wifiDirectManager = (DirectManager) getApplicationContext().getSystemService(DirectManager.WIFI_DIRECT_SERVICE); 43 | 44 | wifiStateReceiver = new BroadcastReceiver() { 45 | @Override 46 | public void onReceive(Context context, Intent intent) { 47 | wifiStateChanged(intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, WifiManager.WIFI_STATE_UNKNOWN)); 48 | } 49 | }; 50 | 51 | wifiDirectStateReceiver = new BroadcastReceiver() { 52 | @Override 53 | public void onReceive(Context context, Intent intent) { 54 | wifiDirectStateChanged(intent.getIntExtra(DirectManager.EXTRA_DIRECT_STATE, DirectManager.DIRECT_STATE_UNKNOWN)); 55 | } 56 | }; 57 | 58 | groupCreateSuccessReceiver = new BroadcastReceiver() { 59 | @Override 60 | public void onReceive(Context context, Intent intent) { 61 | groupCreated((DirectConfiguration) intent.getParcelableExtra(DirectManager.EXTRA_DIRECT_CONFIG)); 62 | } 63 | }; 64 | 65 | groupCreateFailureReceiver = new BroadcastReceiver() { 66 | @Override 67 | public void onReceive(Context context, Intent intent) { 68 | groupCreateFailed(); 69 | } 70 | }; 71 | 72 | stationConnectedReceiver = new BroadcastReceiver() { 73 | @Override 74 | public void onReceive(Context context, Intent intent) { 75 | stationConnected(intent.getStringExtra(DirectManager.EXTRA_STA_ADDR)); 76 | } 77 | }; 78 | 79 | stationDisconnectedReceiver = new BroadcastReceiver() { 80 | @Override 81 | public void onReceive(Context context, Intent intent) { 82 | stationDisconnected(intent.getStringExtra(DirectManager.EXTRA_STA_ADDR)); 83 | } 84 | }; 85 | 86 | httpServer = new HttpServer(); 87 | } 88 | 89 | @Override 90 | protected void onResume() { 91 | super.onResume(); 92 | registerReceiver(wifiStateReceiver, new IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION)); 93 | registerReceiver(wifiDirectStateReceiver, new IntentFilter(DirectManager.DIRECT_STATE_CHANGED_ACTION)); 94 | registerReceiver(groupCreateSuccessReceiver, new IntentFilter(DirectManager.GROUP_CREATE_SUCCESS_ACTION)); 95 | registerReceiver(groupCreateFailureReceiver, new IntentFilter(DirectManager.GROUP_CREATE_FAILURE_ACTION)); 96 | registerReceiver(stationConnectedReceiver, new IntentFilter(DirectManager.STA_CONNECTED_ACTION)); 97 | registerReceiver(stationDisconnectedReceiver, new IntentFilter(DirectManager.STA_DISCONNECTED_ACTION)); 98 | wifiManager.setWifiEnabled(true); 99 | wifiDirectManager.setDirectEnabled(true); 100 | try { 101 | httpServer.start(); 102 | } catch (IOException e) { 103 | Logger.error("Failed to start HTTP Server: " + e.getMessage()); 104 | } 105 | setAutoPowerOffMode(false); 106 | } 107 | 108 | @Override 109 | protected void onPause() { 110 | super.onPause(); 111 | unregisterReceiver(wifiStateReceiver); 112 | unregisterReceiver(wifiDirectStateReceiver); 113 | unregisterReceiver(groupCreateSuccessReceiver); 114 | unregisterReceiver(groupCreateFailureReceiver); 115 | unregisterReceiver(stationConnectedReceiver); 116 | unregisterReceiver(stationDisconnectedReceiver); 117 | wifiDirectManager.setDirectEnabled(false); 118 | wifiManager.setWifiEnabled(false); 119 | httpServer.stop(); 120 | setAutoPowerOffMode(true); 121 | } 122 | 123 | protected void wifiStateChanged(int state) { 124 | switch (state) { 125 | case WifiManager.WIFI_STATE_ENABLING: 126 | log("Enabling wifi"); 127 | break; 128 | case WifiManager.WIFI_STATE_ENABLED: 129 | log("Wifi enabled"); 130 | break; 131 | } 132 | } 133 | 134 | protected void wifiDirectStateChanged(int state) { 135 | switch (state) { 136 | case DirectManager.DIRECT_STATE_ENABLING: 137 | log("Enabling wifi direct"); 138 | break; 139 | case DirectManager.DIRECT_STATE_ENABLED: 140 | wifiDirectEnabled(); 141 | break; 142 | } 143 | } 144 | 145 | protected void wifiDirectEnabled() { 146 | log("Wifi direct enabled"); 147 | List configurations = wifiDirectManager.getConfigurations(); 148 | if (configurations.isEmpty()) { 149 | log("Error: No configurations found"); 150 | } else { 151 | log("Creating Group"); 152 | wifiDirectManager.startGo(configurations.get(configurations.size() - 1).getNetworkId()); 153 | } 154 | } 155 | 156 | protected void groupCreated(DirectConfiguration configuration) { 157 | log("Group created"); 158 | log("SSID: " + configuration.getSsid()); 159 | log("Key: " + configuration.getPreSharedKey()); 160 | log("Server URL: http://" + MY_IP_ADDRESS + ":" + HttpServer.PORT + "/"); 161 | } 162 | 163 | protected void groupCreateFailed() { 164 | log("Group create failed"); 165 | } 166 | 167 | protected void stationConnected(String address) { 168 | log("Station connected: " + address); 169 | } 170 | 171 | protected void stationDisconnected(String address) { 172 | log("Station disconnected: " + address); 173 | } 174 | 175 | protected void log(String msg) { 176 | textView.append(msg + "\n"); 177 | } 178 | } 179 | -------------------------------------------------------------------------------- /app/src/main/java/info/schnatterer/pmcaFilesystemServer/WifiSettingActivity.java: -------------------------------------------------------------------------------- 1 | package info.schnatterer.pmcaFilesystemServer; 2 | 3 | import android.content.Intent; 4 | import android.net.wifi.WifiManager; 5 | import android.os.Bundle; 6 | 7 | public class WifiSettingActivity extends BaseActivity { 8 | private WifiManager wifiManager; 9 | 10 | @Override 11 | protected void onCreate(Bundle savedInstanceState) { 12 | super.onCreate(savedInstanceState); 13 | 14 | wifiManager = (WifiManager) getApplicationContext().getSystemService(WIFI_SERVICE); 15 | wifiManager.setWifiEnabled(true); 16 | } 17 | 18 | @Override 19 | protected void onResume() { 20 | super.onResume(); 21 | startActivityForResult(new Intent("com.sony.scalar.app.wifisettings.WifiSettings"), 0); 22 | } 23 | 24 | @Override 25 | protected void onActivityResult(int requestCode, int resultCode, Intent data) { 26 | super.onActivityResult(requestCode, resultCode, data); 27 | finish(); 28 | } 29 | 30 | @Override 31 | protected void onDestroy() { 32 | super.onDestroy(); 33 | wifiManager.setWifiEnabled(false); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /app/src/main/res/layout/list.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/layout/log.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/schnatterer/pmcaFilesystemServer/0b9169bcb24067af0e0b790bdea3f322a6dc5dae/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/schnatterer/pmcaFilesystemServer/0b9169bcb24067af0e0b790bdea3f322a6dc5dae/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/schnatterer/pmcaFilesystemServer/0b9169bcb24067af0e0b790bdea3f322a6dc5dae/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/schnatterer/pmcaFilesystemServer/0b9169bcb24067af0e0b790bdea3f322a6dc5dae/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/schnatterer/pmcaFilesystemServer/0b9169bcb24067af0e0b790bdea3f322a6dc5dae/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | FileSystemServer 3 | Start Server via Wifi 4 | Wifi Settings 5 | Start Server via Wifi direct 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/web_hi_res_512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/schnatterer/pmcaFilesystemServer/0b9169bcb24067af0e0b790bdea3f322a6dc5dae/app/src/main/res/web_hi_res_512.png -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | google() 6 | jcenter() 7 | } 8 | dependencies { 9 | classpath 'com.android.tools.build:gradle:3.3.2' 10 | 11 | // NOTE: Do not place your application dependencies here; they belong 12 | // in the individual module build.gradle files 13 | } 14 | } 15 | 16 | allprojects { 17 | repositories { 18 | google() 19 | jcenter() 20 | maven { url "https://jitpack.io" } 21 | } 22 | } 23 | 24 | task clean(type: Delete) { 25 | delete rootProject.buildDir 26 | } 27 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/schnatterer/pmcaFilesystemServer/0b9169bcb24067af0e0b790bdea3f322a6dc5dae/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Sun Feb 24 18:17:43 CET 2019 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.1-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn () { 37 | echo "$*" 38 | } 39 | 40 | die () { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 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 | # Escape application args 158 | save () { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | --------------------------------------------------------------------------------