/***************************************************************************** * Util.java ***************************************************************************** * Copyright © 2011-2014 VLC authors and VideoLAN * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. *****************************************************************************/ package org.videolan.vlc.util; import android.annotation.TargetApi; import android.app.ProgressDialog; import android.content.ContentResolver; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.res.TypedArray; import android.net.Uri; import android.os.Build; import android.preference.PreferenceManager; import android.provider.MediaStore; import android.support.design.widget.Snackbar; import android.text.TextUtils.TruncateAt; import android.util.DisplayMetrics; import android.util.TypedValue; import android.view.View; import android.widget.TextView; import org.videolan.libvlc.LibVLC; import org.videolan.libvlc.Media; import org.videolan.libvlc.util.AndroidUtil; import org.videolan.vlc.MediaLibrary; import org.videolan.vlc.MediaWrapper; import org.videolan.vlc.PlaybackService; import org.videolan.vlc.R; import org.videolan.vlc.VLCApplication; import org.videolan.vlc.gui.video.VideoPlayerActivity; import java.io.BufferedReader; import java.io.Closeable; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; public class Util { public final static String TAG = "VLC/Util"; private static final AtomicInteger sNextGeneratedId = new AtomicInteger(1); public static final String ACTION_SCAN_START = "org.videolan.vlc.gui.ScanStart"; public static final String ACTION_SCAN_STOP = "org.videolan.vlc.gui.ScanStop"; /** Print an on-screen message to alert the user */ public static void snacker(View view, int stringId) { Snackbar.make(view, stringId, Snackbar.LENGTH_SHORT).show(); } /** Print an on-screen message to alert the user */ public static void snacker(View view, String message) { Snackbar.make(view, message, Snackbar.LENGTH_SHORT).show(); } public static int convertPxToDp(int px) { DisplayMetrics metrics = VLCApplication.getAppResources().getDisplayMetrics(); float logicalDensity = metrics.density; int dp = Math.round(px / logicalDensity); return dp; } public static int convertDpToPx(int dp) { return Math.round( TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, VLCApplication.getAppResources().getDisplayMetrics()) ); } public static String readAsset(String assetName, String defaultS) { InputStream is = null; BufferedReader r = null; try { is = VLCApplication.getAppResources().getAssets().open(assetName); r = new BufferedReader(new InputStreamReader(is, "UTF8")); StringBuilder sb = new StringBuilder(); String line = r.readLine(); if(line != null) { sb.append(line); line = r.readLine(); while(line != null) { sb.append('\n'); sb.append(line); line = r.readLine(); } } return sb.toString(); } catch (IOException e) { return defaultS; } finally { close(is); close(r); } } /** * Get a resource id from an attribute id. * @param context * @param attrId * @return the resource id */ public static int getResourceFromAttribute(Context context, int attrId) { TypedArray a = context.getTheme().obtainStyledAttributes(new int[] {attrId}); int resId = a.getResourceId(0, 0); a.recycle(); return resId; } /** * Get a color id from an attribute id. * @param context * @param attrId * @return the color id */ public static int getColorFromAttribute(Context context, int attrId) { return VLCApplication.getAppResources().getColor(getResourceFromAttribute(context, attrId)); } /** * Set the alignment mode of the specified TextView with the desired align * mode from preferences. * * See @array/audio_title_alignment_values * * @param alignMode Align mode as read from preferences * @param t Reference to the textview */ public static void setAlignModeByPref(int alignMode, TextView t) { if(alignMode == 1) t.setEllipsize(TruncateAt.END); else if(alignMode == 2) t.setEllipsize(TruncateAt.START); else if(alignMode == 3) { t.setEllipsize(TruncateAt.MARQUEE); t.setMarqueeRepeatLimit(-1); t.setSelected(true); } } /** * Generate a value suitable for use in {@link #setId(int)}. * This value will not collide with ID values generated at build time by aapt for R.id. * * @return a generated ID value */ public static int generateViewId() { for (;;) { final int result = sNextGeneratedId.get(); // aapt-generated IDs have the high byte nonzero; clamp to the range under that. int newValue = result + 1; if (newValue > 0x00FFFFFF) newValue = 1; // Roll over to 1, not 0. if (sNextGeneratedId.compareAndSet(result, newValue)) { return result; } } } public static void actionScanStart() { Intent intent = new Intent(); intent.setAction(ACTION_SCAN_START); VLCApplication.getAppContext().sendBroadcast(intent); } public static void actionScanStop() { Intent intent = new Intent(); intent.setAction(ACTION_SCAN_STOP); VLCApplication.getAppContext().sendBroadcast(intent); } private static class DialogCallback implements PlaybackService.Client.Callback { private final ProgressDialog dialog; final private PlaybackService.Client mClient; final private Runnable mRunnable; private interface Runnable { void run(PlaybackService service); } private DialogCallback(Context context, Runnable runnable) { mClient = new PlaybackService.Client(context, this); mRunnable = runnable; this.dialog = ProgressDialog.show( context, context.getApplicationContext().getString(R.string.loading) + "…", context.getApplicationContext().getString(R.string.please_wait), true); dialog.setCancelable(true); dialog.setOnCancelListener(new DialogInterface.OnCancelListener() { @Override public void onCancel(DialogInterface dialog) { mClient.disconnect(); } }); mClient.connect(); } @Override public void onConnected(PlaybackService service) { mRunnable.run(service); dialog.dismiss(); } @Override public void onDisconnected() { dialog.dismiss(); } } public static void openMedia(final Context context, final MediaWrapper media){ if (media == null) return; if (media.getType() == MediaWrapper.TYPE_VIDEO) VideoPlayerActivity.start(context, media.getUri(), media.getTitle()); else if (media.getType() == MediaWrapper.TYPE_AUDIO) { new DialogCallback(context, new DialogCallback.Runnable() { @Override public void run(PlaybackService service) { service.load(media); } }); } } public static void openList(final Context context, final List<MediaWrapper> list, final int position){ new DialogCallback(context, new DialogCallback.Runnable() { @Override public void run(PlaybackService service) { service.load(list, position); } }); } public static void openStream(final Context context, final String uri){ new DialogCallback(context, new DialogCallback.Runnable() { @Override public void run(PlaybackService service) { service.loadLocation(uri); } }); } private static String getMediaString(Context ctx, int id) { if (ctx != null) return ctx.getResources().getString(id); else { switch (id) { case R.string.unknown_artist: return "Unknown Artist"; case R.string.unknown_album: return "Unknown Album"; case R.string.unknown_genre: return "Unknown Genre"; default: return ""; } } } public static String getMediaArtist(Context ctx, MediaWrapper media) { final String artist = media.getArtist(); return artist != null ? artist : getMediaString(ctx, R.string.unknown_artist); } public static String getMediaReferenceArtist(Context ctx, MediaWrapper media) { final String artist = media.getReferenceArtist(); return artist != null ? artist : getMediaString(ctx, R.string.unknown_artist); } public static String getMediaAlbumArtist(Context ctx, MediaWrapper media) { final String albumArtist = media.getAlbumArtist(); return albumArtist != null ? albumArtist : getMediaString(ctx, R.string.unknown_artist); } public static String getMediaAlbum(Context ctx, MediaWrapper media) { final String album = media.getAlbum(); return album != null ? album : getMediaString(ctx, R.string.unknown_album); } public static String getMediaGenre(Context ctx, MediaWrapper media) { final String genre = media.getGenre(); return genre != null ? genre : getMediaString(ctx, R.string.unknown_genre); } public static String getMediaSubtitle(Context ctx, MediaWrapper media) { if (media.getType() == MediaWrapper.TYPE_AUDIO) return media.getNowPlaying() != null ? media.getNowPlaying() : getMediaArtist(ctx, media) + " - " + getMediaAlbum(ctx, media); else return ""; } @TargetApi(android.os.Build.VERSION_CODES.GINGERBREAD) public static void commitPreferences(SharedPreferences.Editor editor){ if (AndroidUtil.isGingerbreadOrLater()) editor.apply(); else editor.commit(); } @TargetApi(Build.VERSION_CODES.HONEYCOMB) public static boolean deleteFile (String path){ boolean deleted = false; path = Uri.decode(Strings.removeFileProtocole(path)); //Delete from Android Medialib, for consistency with device MTP storing and other apps listing content:// media if (AndroidUtil.isHoneycombOrLater()){ ContentResolver cr = VLCApplication.getAppContext().getContentResolver(); String[] selectionArgs = { path }; deleted = cr.delete(MediaStore.Files.getContentUri("external"), MediaStore.Files.FileColumns.DATA + "=?", selectionArgs) > 0; } File file = new File(path); if (file.exists()) deleted |= file.delete(); return deleted; } public static boolean recursiveDelete(Context context, File fileOrDirectory) { if (fileOrDirectory.isDirectory()) { for (File child : fileOrDirectory.listFiles()) recursiveDelete(context, child); return fileOrDirectory.delete(); } else { return deleteFile (fileOrDirectory.getPath()); } } public static boolean close(Closeable closeable) { if (closeable != null) { try { closeable.close(); return true; } catch (IOException e) { return false; } } else { return false; } } public static boolean canWrite(String path){ if (path == null) return false; if (path.startsWith("file://")) path = path.substring(7); if (!path.startsWith("/")) return false; if (path.startsWith(AndroidDevices.EXTERNAL_PUBLIC_DIRECTORY)) return true; if (AndroidUtil.isLolliPopOrLater()) return false; File file = new File(path); return (file.exists() && file.canWrite()); } public static boolean isCallable(Intent intent) { List<ResolveInfo> list = VLCApplication.getAppContext().getPackageManager().queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY); return list.size() > 0; } public static boolean isBlackThemeEnabled() { SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(VLCApplication.getAppContext()); return pref.getBoolean("enable_black_theme", false); } }