commit c7fd9770cde2b3646741c81aef1a62302e4e2d21 Author: Suherdy Yacob Date: Fri Dec 20 09:06:59 2024 +0700 first commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..aa724b7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,15 @@ +*.iml +.gradle +/local.properties +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +.DS_Store +/build +/captures +.externalNativeBuild +.cxx +local.properties diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..26d3352 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..b3405b3 --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +My Application \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..b589d56 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/deploymentTargetSelector.xml b/.idea/deploymentTargetSelector.xml new file mode 100644 index 0000000..b268ef3 --- /dev/null +++ b/.idea/deploymentTargetSelector.xml @@ -0,0 +1,10 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..0897082 --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,19 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/migrations.xml b/.idea/migrations.xml new file mode 100644 index 0000000..f8051a6 --- /dev/null +++ b/.idea/migrations.xml @@ -0,0 +1,10 @@ + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..0ad17cb --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,10 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/other.xml b/.idea/other.xml new file mode 100644 index 0000000..b45a6e0 --- /dev/null +++ b/.idea/other.xml @@ -0,0 +1,340 @@ + + + + + + \ No newline at end of file diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 0000000..42afabf --- /dev/null +++ b/app/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/app/build.gradle.kts b/app/build.gradle.kts new file mode 100644 index 0000000..681e29f --- /dev/null +++ b/app/build.gradle.kts @@ -0,0 +1,47 @@ +plugins { + alias(libs.plugins.android.application) +} + +android { + namespace = "com.example.myapplication" + compileSdk = 34 + + defaultConfig { + applicationId = "com.example.myapplication" + minSdk = 24 + targetSdk = 34 + versionCode = 1 + versionName = "1.0" + + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + } + + buildTypes { + release { + isMinifyEnabled = false + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro" + ) + } + } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 + } + buildFeatures { + viewBinding = true + } +} + +dependencies { + + implementation(libs.appcompat) + implementation(libs.material) + implementation(libs.constraintlayout) + implementation(libs.navigation.fragment) + implementation(libs.navigation.ui) + testImplementation(libs.junit) + androidTestImplementation(libs.ext.junit) + androidTestImplementation(libs.espresso.core) +} \ No newline at end of file diff --git a/app/libs/IminLibs1.0.20.jar b/app/libs/IminLibs1.0.20.jar new file mode 100644 index 0000000..04113ee Binary files /dev/null and b/app/libs/IminLibs1.0.20.jar differ diff --git a/app/libs/NeoStraElectronicSDK-3-v1.3_2302281129.jar b/app/libs/NeoStraElectronicSDK-3-v1.3_2302281129.jar new file mode 100644 index 0000000..c177b75 Binary files /dev/null and b/app/libs/NeoStraElectronicSDK-3-v1.3_2302281129.jar differ diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 0000000..481bb43 --- /dev/null +++ b/app/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/app/src/androidTest/java/com/example/myapplication/ExampleInstrumentedTest.java b/app/src/androidTest/java/com/example/myapplication/ExampleInstrumentedTest.java new file mode 100644 index 0000000..982ba51 --- /dev/null +++ b/app/src/androidTest/java/com/example/myapplication/ExampleInstrumentedTest.java @@ -0,0 +1,26 @@ +package com.example.myapplication; + +import android.content.Context; + +import androidx.test.platform.app.InstrumentationRegistry; +import androidx.test.ext.junit.runners.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import static org.junit.Assert.*; + +/** + * Instrumented test, which will execute on an Android device. + * + * @see Testing documentation + */ +@RunWith(AndroidJUnit4.class) +public class ExampleInstrumentedTest { + @Test + public void useAppContext() { + // Context of the app under test. + Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); + assertEquals("com.example.myapplication", appContext.getPackageName()); + } +} \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..23d0d38 --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/java/com/example/myapplication/DifferentDisplay.java b/app/src/main/java/com/example/myapplication/DifferentDisplay.java new file mode 100644 index 0000000..abf4f50 --- /dev/null +++ b/app/src/main/java/com/example/myapplication/DifferentDisplay.java @@ -0,0 +1,65 @@ +package com.example.myapplication; + +import android.annotation.SuppressLint; +import android.app.Presentation; +import android.content.Context; +import android.os.Build; +import android.os.Bundle; +import android.view.Display; +import android.view.WindowManager; +import android.webkit.WebChromeClient; +import android.webkit.WebSettings; +import android.webkit.WebView; +import android.widget.ImageView; +import android.widget.TextView; +import android.widget.VideoView; + + +@SuppressLint("NewApi") +public class DifferentDisplay extends Presentation { + + private TextView text; + private ImageView image; + private VideoView video; + + public DifferentDisplay(Context outerContext, Display display) { + super(outerContext, display); + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.display_layout); + //此功能作用于主屏Activity返回桌面后,副屏View仍然显示 + //This function is used to display the secondary + // screen View after the main screen activity returns to the desktop + if(Build.VERSION.SDK_INT >=32){ + + }else if (Build.VERSION.SDK_INT>=26){ + // 画中画等详细请查看android sdk For details such as picture in picture, please check the android sdk + getWindow().setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY); + }else { + // 8.0 以下的安卓版本要实现上述功能使用以下api Android versions below 8.0 use the following apis to achieve the above functions + getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY); + } + + WebView myWebView = (WebView) findViewById(R.id.webview2); + + myWebView.setWebViewClient(new MyWebViewClient()); + myWebView.setWebChromeClient(new WebChromeClient()); + WebSettings webSettings = myWebView.getSettings(); + webSettings.setJavaScriptEnabled(true); + webSettings.setLoadWithOverviewMode(true); + webSettings.setDomStorageEnabled(true); + webSettings.setUseWideViewPort(true); + webSettings.setDefaultTextEncodingName("utf-8"); + webSettings.setUserAgentString("Desktop"); + webSettings.setBuiltInZoomControls(true); + webSettings.setDisplayZoomControls(false); + webSettings.setSupportMultipleWindows(true); + webSettings.setJavaScriptCanOpenWindowsAutomatically(true); + myWebView.loadUrl("https://odoodev.mapan.co.id"); + } + + +} diff --git a/app/src/main/java/com/example/myapplication/MainActivity.java b/app/src/main/java/com/example/myapplication/MainActivity.java new file mode 100644 index 0000000..d3232e6 --- /dev/null +++ b/app/src/main/java/com/example/myapplication/MainActivity.java @@ -0,0 +1,116 @@ +package com.example.myapplication; + +import android.annotation.SuppressLint; +import android.app.Presentation; +import android.content.Context; +import android.content.Intent; +import android.hardware.display.DisplayManager; +import android.media.MediaRouter; +import android.os.Bundle; + +import com.google.android.material.snackbar.Snackbar; + +import androidx.appcompat.app.AppCompatActivity; + +import android.util.Log; +import android.view.Display; +import android.view.View; + +import androidx.navigation.NavController; +import androidx.navigation.Navigation; +import androidx.navigation.ui.AppBarConfiguration; +import androidx.navigation.ui.NavigationUI; + +import com.example.myapplication.databinding.ActivityMainBinding; + +import android.view.Menu; +import android.view.MenuItem; +import android.webkit.WebChromeClient; +import android.webkit.WebSettings; +import android.webkit.WebView; +import android.widget.Toast; + +public class MainActivity extends AppCompatActivity { + + private AppBarConfiguration appBarConfiguration; + private ActivityMainBinding binding; + private Presentation presentation; + + @SuppressLint("SetJavaScriptEnabled") + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + binding = ActivityMainBinding.inflate(getLayoutInflater()); + setContentView(binding.getRoot()); + + setSupportActionBar(binding.toolbar); + + WebView myWebView = (WebView) findViewById(R.id.webview); + + myWebView.setWebViewClient(new MyWebViewClient()); + myWebView.setWebChromeClient(new WebChromeClient()); + WebSettings webSettings = myWebView.getSettings(); + webSettings.setJavaScriptEnabled(true); + webSettings.setLoadWithOverviewMode(true); + webSettings.setDomStorageEnabled(true); + webSettings.setUseWideViewPort(true); + webSettings.setDefaultTextEncodingName("utf-8"); + webSettings.setUserAgentString("Desktop"); + webSettings.setBuiltInZoomControls(true); + webSettings.setDisplayZoomControls(false); + webSettings.setSupportMultipleWindows(true); + webSettings.setJavaScriptCanOpenWindowsAutomatically(true); + myWebView.loadUrl("https://odoodev.mapan.co.id"); + + if (presentation != null) { + presentation.cancel(); + presentation = null; + return; + } + + binding.fab.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + dualScreenFunction(view); + } + }); + } + + public void dualScreenFunction(View view){ + DisplayManager mDisplayManager = (DisplayManager) getSystemService(Context.DISPLAY_SERVICE); + Display[] displays = mDisplayManager.getDisplays(DisplayManager.DISPLAY_CATEGORY_PRESENTATION); + if (displays != null && getPresentationDisplays() != null) { + presentation = new DifferentDisplay(getApplicationContext(), getPresentationDisplays()); + presentation.show(); + } else { + Toast.makeText(view.getContext(), "no second screen", Toast.LENGTH_SHORT).show(); + } + } + + public Display getPresentationDisplays() { + DisplayManager mDisplayManager = (DisplayManager) getSystemService(Context.DISPLAY_SERVICE); + Display[] displays = mDisplayManager.getDisplays(); + if (displays != null) { + for (int i = 0; i < displays.length; i++) { + //Log.e(TAG, "屏幕==>" + displays[i] + " Flag:==> " + displays[i].getFlags()); + if ((displays[i].getFlags() & Display.FLAG_SECURE) != 0 + && (displays[i].getFlags() & Display.FLAG_SUPPORTS_PROTECTED_BUFFERS) != 0 + && (displays[i].getFlags() & Display.FLAG_PRESENTATION) != 0) { + //Log.e(TAG, "第一个真实存在的副屏屏幕==> " + displays[i]); + return displays[i]; + } + } + } + return null; + } + + @Override + protected void onDestroy() { + super.onDestroy(); + if (presentation != null) { + presentation.cancel(); + presentation = null; + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/myapplication/MyWebChromeClient.java b/app/src/main/java/com/example/myapplication/MyWebChromeClient.java new file mode 100644 index 0000000..9a26690 --- /dev/null +++ b/app/src/main/java/com/example/myapplication/MyWebChromeClient.java @@ -0,0 +1,59 @@ +package com.example.myapplication; + +import android.app.AlertDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.os.Message; +import android.webkit.JsResult; +import android.webkit.WebChromeClient; +import android.webkit.WebSettings; +import android.webkit.WebView; +import android.webkit.WebViewClient; + +public class MyWebChromeClient extends WebChromeClient { + @Override + public boolean onCreateWindow(WebView view, boolean isDialog, + boolean isUserGesture, Message resultMsg) { + WebView newWebView = new WebView(view.getContext()); + newWebView.getSettings().setJavaScriptEnabled(true); + newWebView.getSettings().setSupportZoom(true); + newWebView.getSettings().setBuiltInZoomControls(true); + newWebView.getSettings().setPluginState(WebSettings.PluginState.ON); + newWebView.getSettings().setSupportMultipleWindows(true); + view.addView(newWebView); + WebView.WebViewTransport transport = (WebView.WebViewTransport) resultMsg.obj; + transport.setWebView(newWebView); + resultMsg.sendToTarget(); + + newWebView.setWebViewClient(new WebViewClient() { + @Override + public boolean shouldOverrideUrlLoading(WebView view, String url) { + view.loadUrl(url); + return true; + } + }); + + return true; + } + + @Override + public boolean onJsAlert(WebView view, String url, String message, JsResult result) + { + final JsResult finalRes = result; + new AlertDialog.Builder(view.getContext()) + .setMessage(message) + .setPositiveButton(android.R.string.ok, + new AlertDialog.OnClickListener() + { + @Override + public void onClick(DialogInterface dialog, int which) { + finalRes.confirm(); + } + }) + .setCancelable(false) + .create() + .show(); + return true; + } +} + diff --git a/app/src/main/java/com/example/myapplication/MyWebViewClient.java b/app/src/main/java/com/example/myapplication/MyWebViewClient.java new file mode 100644 index 0000000..5d1d116 --- /dev/null +++ b/app/src/main/java/com/example/myapplication/MyWebViewClient.java @@ -0,0 +1,18 @@ +package com.example.myapplication; + +import static androidx.core.content.ContextCompat.startActivity; + +import android.content.Intent; +import android.webkit.WebResourceRequest; +import android.webkit.WebView; +import android.webkit.WebViewClient; + +public class MyWebViewClient extends WebViewClient { + @Override + public boolean shouldOverrideUrlLoading(WebView view, String url) { + view.loadUrl(url); + return true; + } + + +} diff --git a/app/src/main/java/com/example/myapplication/ScreenActivity.java b/app/src/main/java/com/example/myapplication/ScreenActivity.java new file mode 100644 index 0000000..aa1a4b9 --- /dev/null +++ b/app/src/main/java/com/example/myapplication/ScreenActivity.java @@ -0,0 +1,123 @@ +package com.example.myapplication; + +import android.app.Presentation; +import android.content.Context; +import android.content.Intent; +import android.hardware.display.DisplayManager; +import android.net.Uri; +import android.os.Build; +import android.os.Bundle; +import android.provider.Settings; +import android.util.Log; +import android.view.Display; +import android.view.View; +import android.widget.Button; +import android.widget.ImageView; +import android.widget.MediaController; +import android.widget.TextView; +import android.widget.Toast; +import android.widget.VideoView; +import androidx.appcompat.app.AppCompatActivity; + +/** + * @author :Chenjk + * @version 1.0 + * @createTime :2023/12/29 10:55 + **/ +public class ScreenActivity extends AppCompatActivity { + private static final String TAG = "display_demo"; + private Presentation presentation; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_screen); + Button showDisplay = findViewById(R.id.btn_open_display); + Button showText = findViewById(R.id.btn_show_text); + Button showPic = findViewById(R.id.btn_show_pic); + Button showVideo = findViewById(R.id.btn_show_video); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && Build.VERSION.SDK_INT < Build.VERSION_CODES.S_V2) { + if (!Settings.canDrawOverlays(this)) { + Toast.makeText(this, "请同意显示窗口权限", Toast.LENGTH_SHORT).show(); + startActivity(new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION)); + } + } + + showDisplay.setOnClickListener(v -> { + if (presentation != null) { + presentation.cancel(); + presentation = null; + return; + } +// showSecondByMediaRouter(MainActivity.this); + showSecondByDisplayManager(ScreenActivity.this); + + }); + } + + +// private void showSecondByMediaRouter(Context context){ +// MediaRouter mediaRouter = (MediaRouter) context.getSystemService(Context.MEDIA_ROUTER_SERVICE); +// MediaRouter.RouteInfo route = mediaRouter.getSelectedRoute(MediaRouter.ROUTE_TYPE_LIVE_VIDEO); +// if (route != null) { +// Display presentationDisplay = route.getPresentationDisplay(); +// if (presentationDisplay != null) { +// presentation = new DifferentDisplay(context, presentationDisplay); +// presentation.show(); +// } +// } +// } + + private void showSecondByDisplayManager(Context context) { + DisplayManager mDisplayManager = (DisplayManager) getSystemService(Context.DISPLAY_SERVICE); + Display[] displays = mDisplayManager.getDisplays(DisplayManager.DISPLAY_CATEGORY_PRESENTATION); + if (displays != null && getPresentationDisplays() != null) { + presentation = new DifferentDisplay(getApplicationContext(), getPresentationDisplays()); + presentation.show(); + } else { + Toast.makeText(ScreenActivity.this, "no second screen", Toast.LENGTH_SHORT).show(); + } + /*副屏的Window*/ + + } + + public Display getPresentationDisplays() { + DisplayManager mDisplayManager = (DisplayManager) getSystemService(Context.DISPLAY_SERVICE); + Display[] displays = mDisplayManager.getDisplays(); + if (displays != null) { + for (int i = 0; i < displays.length; i++) { + Log.e(TAG, "屏幕==>" + displays[i] + " Flag:==> " + displays[i].getFlags()); + if ((displays[i].getFlags() & Display.FLAG_SECURE) != 0 + && (displays[i].getFlags() & Display.FLAG_SUPPORTS_PROTECTED_BUFFERS) != 0 + && (displays[i].getFlags() & Display.FLAG_PRESENTATION) != 0) { + Log.e(TAG, "第一个真实存在的副屏屏幕==> " + displays[i]); + return displays[i]; + } + } + } + + return null; + } + +// private void showSecondByActivity(Context context){ +// ActivityOptions options = ActivityOptions.makeBasic(); +// MediaRouter mediaRouter = (MediaRouter) context.getSystemService(Context.MEDIA_ROUTER_SERVICE); +// MediaRouter.RouteInfo route = mediaRouter.getSelectedRoute(MediaRouter.ROUTE_TYPE_LIVE_VIDEO); +// if (route != null) { +// Display presentationDisplay = route.getPresentationDisplay(); +// options.setLaunchDisplayId(presentationDisplay.getDisplayId()); +// Intent intent = new Intent("android.intent.action.MUSIC_PLAYER"); +// intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); +// startActivity(intent, options.toBundle()); +// } +// } + + @Override + protected void onDestroy() { + super.onDestroy(); + if (presentation != null) { + presentation.cancel(); + presentation = null; + } + } +} \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000..07d5da9 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_launcher_foreground.xml b/app/src/main/res/drawable/ic_launcher_foreground.xml new file mode 100644 index 0000000..2b068d1 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_foreground.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml new file mode 100644 index 0000000..22a2e05 --- /dev/null +++ b/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_screen.xml b/app/src/main/res/layout/activity_screen.xml new file mode 100644 index 0000000..dbe7e40 --- /dev/null +++ b/app/src/main/res/layout/activity_screen.xml @@ -0,0 +1,65 @@ + + + +