从Android N开始,添加了分屏和画中画功能。
在手持设备上,两个应用可以在“分屏”模式中左右并排或上下并排显示。
在电视设备上,应用可以使用“画中画”模式,如:用户与另一个应用交互的同时继续播放视频。分屏,用户可以拖动两个应用之间的分割线,放大其中一个应用,同时缩小另一个。分屏情况下,通过拖动两个应用的分割线,应用可占屏幕的1/3、 1/2、 2/3。
在清单文件的 或 节点中设置该属性,启用或禁用多窗口显示:
android:resizeableActivity=["true" | "false"]
如果该属性设置为 true,Activity 将能以分屏和自由形状模式启动。 如果此属性设置为 false,Activity 将不支持多窗口模式。 如果该值为 false,且用户尝试在多窗口模式下启动 Activity,该 Activity 将全屏显示。
若不在Manifest的Activity声明以下属性,应用分屏大小改变时:
* 如果未声明,则Activity都会销毁重启。
* 如果已声明,则Activity不会销毁重启,
android:configChanges="smallestScreenSize|orientation|screenSize|screenLayout"
在分屏情况下,分屏时,用户点击分屏的某个界面,则获取
* 得到焦点的Activity 由 onPause -> onResume
* 失去焦点的Activity 由 onResume -> onPause
获取屏幕宽度
private void initScreenWidthDp() {
WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics dm = new DisplayMetrics();
wm.getDefaultDisplay().getMetrics(dm);
sScreenWidthDp = (int) (dm.widthPixels / dm.density);
}
计算处于几分屏
public class ScreenManager {
public static ScreenStatus sScreenStatus = ScreenStatus.FULL;
/**
* 0.6 < ratio < 0.7 2/3屏
* 0.45 < ratio < 0.55 1/2屏
* 0.3 < ratio < 0.4 1/3屏
* 其他情况为全屏
* @param widthDp 当前界面的宽度
* */
public static void setScreenStatusByWidth(int widthDp) {
float ratio = (float) widthDp / FileBrowseApplication.getScreenWidthDp();
if (ratio > 0.6 && ratio < 0.7) {
sScreenStatus = ScreenStatus.TWO_THIRDS;
} else if (ratio < 0.55 && ratio > 0.45) {
sScreenStatus = ScreenStatus.HALF;
} else if (ratio < 0.4 && ratio > 0.3) {
sScreenStatus = ScreenStatus.ONE_THIRD;
} else {
sScreenStatus = ScreenStatus.FULL;
}
}
public static ScreenStatus getScreenStatus() {
return sScreenStatus;
}
public enum ScreenStatus {
ONE_THIRD, HALF, TWO_THIRDS, FULL
}
}
屏幕大小变化时,设置几分屏
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
ScreenManager.setScreenStatusByWidth(newConfig.screenWidthDp);
changeViewByStatus();
}
Notice:在onCreate()中也要设置分屏状态, 否则在分屏情况下打开某个Activity会导致分屏状态不对。
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (Utils.isGEandroid24()) {
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
initMultiWindow();
}
}, 0);
}
}
private void initMultiWindow() {
WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics dm = new DisplayMetrics();
wm.getDefaultDisplay().getMetrics(dm);
int widthDp = (int) (dm.widthPixels / dm.density);
ScreenManager.setScreenStatusByWidth(widthDp);
if (Utils.isGEandroid24() && isInMultiWindowMode()) {
changeViewByStatus();
}
}
在Android 7.0及以上系统执行以下代码,使用Uri.fromFile(file)传递文件路径给第三方应用,将直接抛出FileUriExposedException异常(应用内使用则不存在该问题)。
Intent intent = new Intent(Intent.ACTION_VIEW);
File file = new File(fileItemInfo.getFilePath());
String mimeType = MimeHelper.getMimeType(fileItemInfo);
intent.setDataAndType(Uri.fromFile(file), mimeType);
startActivity(intent);
(1)在AndroidManifest中声明
"android.support.v4.content.FileProvider"
android:authorities="com.seewo.easifinder.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
provider>
其中file_paths.xml内容如下:
"1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<root-path name="root" path="" />
<files-path name="files" path="" />
<cache-path name="cache" path="" />
<external-path name="external" path="" />
<external-files-path name="name" path="path" />
<external-cache-path name="name" path="path" />
paths>
“”为空代表可以使用所有文件,若path不为“”,如:
"external" path="pics" />
其代表的目录即为:Environment.getExternalStorageDirectory()/pics,其他同理。
当这么声明以后,代码可以使用你所声明的当前文件夹以及其子文件夹。
(2)在代码中使用
如打开内存卡根目录的文件,如 test.jpg, 则其文件路径为 content://com.seewo.easifinder.fileprovider/external/test.jpg
public static void setIntentDataAndType(Context context, Intent intent, String type, File file, boolean canWrite) {
if (Utils.isGEandroid24()) {
intent.setDataAndType(getUriForFile(context, file), type);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
if (canWrite) {
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
}
} else {
intent.setDataAndType(Uri.fromFile(file), type);
}
}
private static Uri getUriForFile24(Context context, File file) {
Uri fileUri = FileProvider.getUriForFile(context, context.getPackageName() + ".fileprovider", file);
return fileUri;
}
(1)获取文件类型
Uri returnUri = getIntent().getData();
String mimeType = getContentResolver().getType(returnUri);
(2)获取文件大小和名字
Uri uri = getIntent().getData();
Cursor cursor = getContentResolver().query(uri, null, null, null, null);
cursor.moveToFirst();
String name = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME));
String size = cursor.getString(cursor.getColumnIndex(OpenableColumns.SIZE));
(3)获取文件句柄
ParcelFileDescriptor mParcelFileDescriptor = null;
try {
mParcelFileDescriptor = getContentResolver().openFileDescriptor(uri, "r");
} catch (FileNotFoundException e) {
e.printStackTrace();
}
FileDescriptor fd = mParcelFileDescriptor.getFileDescriptor();
FileInputStream fis = new FileInputStream(fd);
(1) 全局使用file://格式,在Applicaition中声明:
private void disableDeathOnFileUriExposure(){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
try {
Method m = StrictMode.class.getMethod("disableDeathOnFileUriExposure");
m.invoke(null);
} catch (Exception e) {
e.printStackTrace();
}
}
}
(2) 局部使用file://格式
public void safelyStartActivity(TargetInfo cti) {
// We're dispatching intents that might be coming from legacy apps, so
// don't kill ourselves.
StrictMode.disableDeathOnFileUriExposure();
try {
safelyStartActivityInternal(cti);
} finally {
StrictMode.enableDeathOnFileUriExposure();
}
}