├── .gitattributes ├── .gitignore ├── README.md ├── WeChatVideoRecorder.iml ├── app ├── .gitignore ├── app.iml ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── info │ │ └── smemo │ │ └── wechatvideorecorder │ │ └── ApplicationTest.java │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── info │ │ └── smemo │ │ └── wechatvideorecorder │ │ ├── MainActivity.java │ │ ├── PhoneManager.java │ │ ├── PhoneUtil.java │ │ ├── StringUtil.java │ │ ├── VideoRecordActivity.java │ │ └── VideoRecorderView.java │ └── res │ ├── drawable-xxhdpi │ ├── ic_play_action_normal.png │ ├── ic_play_action_pressed.png │ ├── video_bg.png │ ├── video_button.png │ └── video_ok.png │ ├── drawable │ ├── ic_play_action.xml │ ├── video_progress_color_left.xml │ └── video_progress_color_right.xml │ ├── layout │ ├── activity_main.xml │ ├── activity_record.xml │ └── ui_recorder.xml │ ├── menu │ └── menu_main.xml │ ├── mipmap-hdpi │ └── ic_launcher.png │ ├── mipmap-mdpi │ └── ic_launcher.png │ ├── mipmap-xhdpi │ └── ic_launcher.png │ ├── mipmap-xxhdpi │ └── ic_launcher.png │ ├── values-w820dp │ └── dimens.xml │ └── values │ ├── dimens.xml │ ├── strings.xml │ └── styles.xml ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Built application files 2 | *.apk 3 | *.ap_ 4 | 5 | # Files for the Dalvik VM 6 | *.dex 7 | 8 | # Java class files 9 | *.class 10 | 11 | # Generated files 12 | bin/ 13 | gen/ 14 | 15 | # Gradle files 16 | .gradle/ 17 | build/ 18 | 19 | # Local configuration file (sdk path, etc) 20 | local.properties 21 | 22 | # Proguard folder generated by Eclipse 23 | proguard/ 24 | 25 | # Log Files 26 | *.log 27 | 28 | # ========================= 29 | # Operating System Files 30 | # ========================= 31 | 32 | # OSX 33 | # ========================= 34 | 35 | .DS_Store 36 | .AppleDouble 37 | .LSOverride 38 | 39 | # Thumbnails 40 | ._* 41 | 42 | # Files that might appear on external disk 43 | .Spotlight-V100 44 | .Trashes 45 | 46 | # Directories potentially created on remote AFP share 47 | .AppleDB 48 | .AppleDesktop 49 | Network Trash Folder 50 | Temporary Items 51 | .apdisk 52 | 53 | # Windows 54 | # ========================= 55 | 56 | # Windows image file caches 57 | Thumbs.db 58 | ehthumbs.db 59 | 60 | # Folder config file 61 | Desktop.ini 62 | 63 | # Recycle Bin used on file shares 64 | $RECYCLE.BIN/ 65 | 66 | # Windows Installer files 67 | *.cab 68 | *.msi 69 | *.msm 70 | *.msp 71 | 72 | # Windows shortcuts 73 | *.lnk 74 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # WeChatVideoRecorder 2 | Android-VideoRecorder 3 | 4 | 仿Android微信录制小视频功能 5 | 6 | 7 | 还有很多地方优化的不好,体验不好。希望大家指导学习,做出最佳效果。 8 | 9 | 下面需要解决的部分: 10 | 11 | 1.视频尺寸,怎么像微信那也是横着的,即宽比高要长 12 | 2.视频压缩,怎么在保证一定清晰度的前提下,尽可能的压缩生成文件的大小 13 | 3.资源的初始化以及释放的合理位置 14 | 15 | #About Devloper 16 | 17 | Neo (http://blog.smemo.info) 18 | -------------------------------------------------------------------------------- /WeChatVideoRecorder.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/app.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 8 | 9 | 10 | 11 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 22 5 | buildToolsVersion '22.0.1' 6 | 7 | defaultConfig { 8 | applicationId "info.smemo.wechatvideorecorder" 9 | minSdkVersion 15 10 | targetSdkVersion 22 11 | versionCode 1 12 | versionName "1.0" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | } 21 | 22 | dependencies { 23 | compile fileTree(include: ['*.jar'], dir: 'libs') 24 | compile 'com.android.support:appcompat-v7:22.2.0' 25 | } 26 | -------------------------------------------------------------------------------- /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 D:\soft\androidsdk/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 | -------------------------------------------------------------------------------- /app/src/androidTest/java/info/smemo/wechatvideorecorder/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package info.smemo.wechatvideorecorder; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 20 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /app/src/main/java/info/smemo/wechatvideorecorder/MainActivity.java: -------------------------------------------------------------------------------- 1 | package info.smemo.wechatvideorecorder; 2 | 3 | import android.app.Activity; 4 | import android.content.Intent; 5 | import android.os.Bundle; 6 | 7 | 8 | public class MainActivity extends Activity { 9 | 10 | @Override 11 | protected void onCreate(Bundle savedInstanceState) { 12 | super.onCreate(savedInstanceState); 13 | setContentView(R.layout.activity_main); 14 | startActivity(new Intent(this,VideoRecordActivity.class)); 15 | 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /app/src/main/java/info/smemo/wechatvideorecorder/PhoneManager.java: -------------------------------------------------------------------------------- 1 | package info.smemo.wechatvideorecorder; 2 | 3 | import android.app.ActivityManager; 4 | import android.app.DownloadManager; 5 | import android.app.NotificationManager; 6 | import android.content.Context; 7 | import android.location.LocationManager; 8 | import android.net.ConnectivityManager; 9 | import android.net.NetworkInfo; 10 | import android.net.wifi.WifiInfo; 11 | import android.net.wifi.WifiManager; 12 | import android.telephony.TelephonyManager; 13 | import android.view.WindowManager; 14 | 15 | /** 16 | * get all manager from this class 17 | * 18 | */ 19 | public class PhoneManager { 20 | 21 | 22 | /** 23 | * get ActivityManager 24 | */ 25 | public static ActivityManager getActivityManager(Context context){ 26 | if(context==null)return null; 27 | ActivityManager activityManager = (ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE); 28 | return activityManager; 29 | } 30 | 31 | /** 32 | * get WindowManager 33 | */ 34 | public static WindowManager getWindowManger(Context context){ 35 | if(context==null)return null; 36 | WindowManager windowManager = null; 37 | windowManager=(WindowManager)context.getSystemService(Context.WINDOW_SERVICE); 38 | return windowManager; 39 | } 40 | 41 | /** 42 | * get TelephonyManager 43 | */ 44 | public static TelephonyManager getTelephonyManager(Context context){ 45 | if(context==null)return null; 46 | TelephonyManager telephonyManager=null; 47 | telephonyManager=(TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); 48 | return telephonyManager; 49 | } 50 | 51 | /** 52 | * get ConnectivityManager 53 | */ 54 | public static ConnectivityManager getConnectivityManager(Context context){ 55 | if(context==null)return null; 56 | ConnectivityManager connectivityManager=null; 57 | connectivityManager=(ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); 58 | return connectivityManager; 59 | } 60 | 61 | /** 62 | * 63 | */ 64 | public static NetworkInfo getNetworkInfo(Context context){ 65 | if(context==null)return null; 66 | NetworkInfo ni = getConnectivityManager(context).getActiveNetworkInfo(); 67 | return ni; 68 | } 69 | 70 | /** 71 | * wifi's state can change 72 | * so everytime calling this method we must get a new WifiManager 73 | * @param context 74 | * @return 75 | */ 76 | public static WifiManager getWifiManager(Context context){ 77 | if(context==null)return null; 78 | WifiManager wifiManager=null; 79 | wifiManager=(WifiManager) context.getSystemService(Context.WIFI_SERVICE); 80 | return wifiManager; 81 | } 82 | 83 | /** 84 | * get WifiInfo 85 | * @param context 86 | * @return 87 | */ 88 | public static WifiInfo getWifiInfo(Context context){ 89 | if(context==null)return null; 90 | return getWifiManager(context).getConnectionInfo(); 91 | } 92 | 93 | public static LocationManager getLocationManager(Context context) { 94 | if(context==null)return null; 95 | return (LocationManager) context 96 | .getSystemService(Context.LOCATION_SERVICE); 97 | } 98 | 99 | public static NotificationManager getNotificationManager(Context context) { 100 | if(context==null)return null; 101 | return (NotificationManager) context 102 | .getSystemService(Context.NOTIFICATION_SERVICE); 103 | } 104 | 105 | public static DownloadManager getDownloadManager(Context context){ 106 | if(context == null)return null; 107 | DownloadManager downloadManager=null; 108 | downloadManager=(DownloadManager)context.getSystemService(Context.DOWNLOAD_SERVICE); 109 | return downloadManager; 110 | } 111 | 112 | 113 | 114 | } 115 | -------------------------------------------------------------------------------- /app/src/main/java/info/smemo/wechatvideorecorder/PhoneUtil.java: -------------------------------------------------------------------------------- 1 | package info.smemo.wechatvideorecorder; 2 | 3 | import android.content.Context; 4 | import android.hardware.Sensor; 5 | import android.hardware.SensorManager; 6 | import android.location.Criteria; 7 | import android.location.Location; 8 | import android.location.LocationManager; 9 | import android.net.ConnectivityManager; 10 | import android.net.NetworkInfo; 11 | import android.net.wifi.WifiInfo; 12 | import android.net.wifi.WifiManager; 13 | import android.telephony.TelephonyManager; 14 | import android.telephony.cdma.CdmaCellLocation; 15 | import android.telephony.gsm.GsmCellLocation; 16 | import android.util.DisplayMetrics; 17 | import android.view.Display; 18 | import android.view.WindowManager; 19 | import java.util.List; 20 | import java.util.Locale; 21 | 22 | public class PhoneUtil { 23 | 24 | 25 | /** 26 | * 获取传感器列表 type name vendor 27 | * 28 | * @param context 29 | * @return 30 | */ 31 | public static String getSensorList(Context context) { 32 | SensorManager mSensorManager = (SensorManager) context 33 | .getSystemService(Context.SENSOR_SERVICE); 34 | if(null == mSensorManager) 35 | return ""; 36 | List sensors = mSensorManager.getSensorList(Sensor.TYPE_ALL); 37 | StringBuilder builder = new StringBuilder(); 38 | for (Sensor sensor : sensors) 39 | builder.append(sensor.getType() + "," + sensor.getName() + "," 40 | + sensor.getVendor() + "|"); 41 | return builder.toString().substring(0, builder.toString().length() - 1); 42 | } 43 | 44 | public static boolean isOpenNetwork(Context context) { 45 | ConnectivityManager connManager = (ConnectivityManager) context 46 | .getSystemService(Context.CONNECTIVITY_SERVICE); 47 | if (connManager.getActiveNetworkInfo() != null) { 48 | return connManager.getActiveNetworkInfo().isAvailable(); 49 | } else { 50 | return false; 51 | } 52 | } 53 | 54 | /** 55 | * WIFI是否连接 56 | * 57 | * @param context 58 | * @return 59 | */ 60 | public static boolean isWifiConnected(Context context) { 61 | if (context != null) { 62 | ConnectivityManager mConnectivityManager = (ConnectivityManager) context 63 | .getSystemService(Context.CONNECTIVITY_SERVICE); 64 | NetworkInfo mWiFiNetworkInfo = mConnectivityManager 65 | .getNetworkInfo(ConnectivityManager.TYPE_WIFI); 66 | if (mWiFiNetworkInfo != null) { 67 | return mWiFiNetworkInfo.isAvailable(); 68 | } 69 | } 70 | return false; 71 | } 72 | 73 | public static float getDensity(Context context) { 74 | DisplayMetrics displayMetrics = context.getResources() 75 | .getDisplayMetrics(); 76 | return displayMetrics.density; 77 | } 78 | 79 | /** 80 | * 获取当前手机的IMSI号 81 | */ 82 | public static String getIMSI(Context context) { 83 | TelephonyManager telephonyManager = (TelephonyManager) context 84 | .getSystemService(Context.TELEPHONY_SERVICE); 85 | if(null == telephonyManager) 86 | return ""; 87 | String imsi = telephonyManager.getSubscriberId(); 88 | if(StringUtil.isEmpty(imsi)) 89 | return ""; 90 | return imsi; 91 | } 92 | 93 | /** 94 | * 获取当前手机的IMEI号 95 | */ 96 | public static String getIMEI(Context context) { 97 | TelephonyManager telephonyManager = (TelephonyManager) context 98 | .getSystemService(Context.TELEPHONY_SERVICE); 99 | if(null == telephonyManager) 100 | return ""; 101 | String id=telephonyManager.getDeviceId(); 102 | if(StringUtil.isEmpty(id)) 103 | return ""; 104 | return telephonyManager.getDeviceId(); 105 | } 106 | 107 | /** 108 | * 获取当前手机的Mac号 109 | */ 110 | public static String getMac(Context context) { 111 | try { 112 | String macAddress = null; 113 | WifiManager wifiMgr = (WifiManager) context 114 | .getSystemService(Context.WIFI_SERVICE); 115 | WifiInfo info = (null == wifiMgr ? null : wifiMgr.getConnectionInfo()); 116 | if (null != info) { 117 | macAddress = info.getMacAddress(); 118 | if (StringUtil.isEmpty(macAddress)) 119 | return ""; 120 | macAddress = macAddress.replaceAll(":", ""); 121 | macAddress = macAddress.toLowerCase(Locale.CHINA); 122 | return macAddress; 123 | 124 | } 125 | return ""; 126 | }catch (Exception e){ 127 | return ""; 128 | } 129 | } 130 | 131 | /** 132 | * 获取当前手机当前wifi的SSID 133 | */ 134 | public static String getSSIDWithContext(Context context) { 135 | WifiManager mWifi = (WifiManager) context 136 | .getSystemService(Context.WIFI_SERVICE); 137 | WifiInfo iWifi = mWifi.getConnectionInfo(); 138 | if (null == iWifi) 139 | return ""; 140 | String wifiName = iWifi.getSSID(); 141 | if (StringUtil.isEmpty(wifiName)) 142 | return ""; 143 | return wifiName; 144 | } 145 | 146 | /** 147 | * 获取当前连接WIFI的mac地址 148 | * 149 | * @param context 150 | * @return 151 | */ 152 | public static String getSSIDWithMac(Context context) { 153 | WifiManager mWifi = (WifiManager) context 154 | .getSystemService(Context.WIFI_SERVICE); 155 | WifiInfo iWifi = mWifi.getConnectionInfo(); 156 | if (null == iWifi) 157 | return ""; 158 | String mac = iWifi.getBSSID(); 159 | if (StringUtil.isEmpty(mac)) 160 | return ""; 161 | mac = mac.replaceAll(":", ""); 162 | mac = mac.toLowerCase(Locale.CHINA); 163 | return mac; 164 | } 165 | 166 | /** 167 | * 获取手机的信息提供商 168 | */ 169 | public static String getPhoneType(Context context) { 170 | TelephonyManager telManager = (TelephonyManager) context 171 | .getSystemService(Context.TELEPHONY_SERVICE); 172 | String imsi = telManager.getSubscriberId(); 173 | if (StringUtil.isEmpty(imsi)) 174 | return ""; 175 | if (imsi.startsWith("46000") || imsi.startsWith("46002")) { 176 | return "中国移动"; 177 | } else if (imsi.startsWith("46001")) { 178 | return "中国联通"; 179 | } else if (imsi.startsWith("46003")) { 180 | return "中国电信"; 181 | } else { 182 | return ""; 183 | } 184 | } 185 | 186 | /** 187 | * get resolution 188 | * 189 | * @param context 190 | * @return 191 | */ 192 | public static int[] getResolution(Context context) { 193 | int resolution[] = new int[2]; 194 | DisplayMetrics dm = new DisplayMetrics(); 195 | PhoneManager.getWindowManger(context).getDefaultDisplay() 196 | .getMetrics(dm); 197 | resolution[0] = dm.widthPixels; 198 | resolution[1] = dm.heightPixels; 199 | return resolution; 200 | } 201 | 202 | /** 203 | * 判断是否为平板 204 | * 205 | * @return 206 | */ 207 | public static boolean isPad(Context context) { 208 | WindowManager wm = PhoneManager.getWindowManger(context); 209 | Display display = wm.getDefaultDisplay(); 210 | DisplayMetrics dm = new DisplayMetrics(); 211 | display.getMetrics(dm); 212 | double x = Math.pow(dm.widthPixels / dm.xdpi, 2); 213 | double y = Math.pow(dm.heightPixels / dm.ydpi, 2); 214 | // 屏幕尺寸 215 | double screenInches = Math.sqrt(x + y); 216 | // 大于6尺寸则为Pad 217 | if (screenInches >= 6.0) { 218 | return true; 219 | } 220 | return false; 221 | } 222 | 223 | /** 224 | * 获取GPS经纬度坐标 225 | * 226 | * @param context 227 | * @return 228 | */ 229 | public static String getGPSLocation(Context context) { 230 | double[] long_lat = new double[2]; 231 | LocationManager locationManager = null; 232 | boolean gps = false; 233 | try { 234 | // A LocationManager for controlling location (e.g., GPS) updates. 235 | locationManager = PhoneManager.getLocationManager(context); 236 | if (null != locationManager) 237 | gps = locationManager 238 | .isProviderEnabled(LocationManager.GPS_PROVIDER); 239 | Criteria criteria = new Criteria(); 240 | criteria.setAccuracy(Criteria.ACCURACY_FINE);// 高精度 241 | criteria.setAltitudeRequired(false);// 不要求海拔 242 | criteria.setBearingRequired(false);// 不要求方位 243 | criteria.setCostAllowed(true);// 允许有花费 244 | criteria.setPowerRequirement(Criteria.POWER_LOW);// 低功耗 245 | // 从可用的位置提供器中,匹配以上标准的最佳提供器 246 | String provider = locationManager.getBestProvider(criteria, true); 247 | 248 | // 获得最后一次变化的位置 249 | Location location = locationManager.getLastKnownLocation(provider); 250 | if (null == location) { 251 | return "::" + (gps ? 1 : 0); 252 | } 253 | long_lat[0] = location.getLongitude(); 254 | long_lat[1] = location.getLatitude(); 255 | 256 | } catch (Exception e) { 257 | return "error:" + e.toString(); 258 | } 259 | return long_lat[0] + ":" + long_lat[1] + ":" + (gps ? 1 : 0); 260 | } 261 | 262 | public static String getGpsLongitude(Context context) { 263 | if (getGpsData(context) == null) 264 | return ""; 265 | return String.valueOf(getGpsData(context)[0]); 266 | } 267 | 268 | public static String getGpsLatitude(Context context) { 269 | if (getGpsData(context) == null) 270 | return ""; 271 | return String.valueOf(getGpsData(context)[1]); 272 | } 273 | 274 | public static double[] getGpsData(Context context) { 275 | double[] long_lat = new double[2]; 276 | LocationManager locationManager = null; 277 | try { 278 | // A LocationManager for controlling location (e.g., GPS) updates. 279 | locationManager = PhoneManager.getLocationManager(context); 280 | Criteria criteria = new Criteria(); 281 | criteria.setAccuracy(Criteria.ACCURACY_FINE);// 高精度 282 | criteria.setAltitudeRequired(false);// 不要求海拔 283 | criteria.setBearingRequired(false);// 不要求方位 284 | criteria.setCostAllowed(true);// 允许有花费 285 | criteria.setPowerRequirement(Criteria.POWER_LOW);// 低功耗 286 | // 从可用的位置提供器中,匹配以上标准的最佳提供器 287 | String provider = locationManager.getBestProvider(criteria, true); 288 | 289 | // 获得最后一次变化的位置 290 | Location location = locationManager.getLastKnownLocation(provider); 291 | if (null == location) { 292 | return null; 293 | } 294 | long_lat[0] = location.getLongitude(); 295 | long_lat[1] = location.getLatitude(); 296 | 297 | } catch (Exception e) { 298 | return null; 299 | } 300 | 301 | return long_lat; 302 | } 303 | 304 | /** 305 | * 获取基站坐标 306 | * 307 | * @param context 308 | * @return 309 | */ 310 | public static String getLBSLocation(Context context) { 311 | /** 网络编号46000,46002编号(134/159号段):中国移动 46001:中国联通 46003:中国电信 */ 312 | String simOper = ""; 313 | /** 314 | * cid(GMS),lac(GMS),networkid=默认字段(GMS) cid:基站小区号(CDMA) lac:系统标识(CDMA) 315 | * networkid(CDMA) 316 | */ 317 | /** 基站编码 */ 318 | int cid = 0; 319 | /** 位置区域码 */ 320 | int lac = 0; 321 | int networkid = 0; 322 | 323 | try { 324 | TelephonyManager tm = PhoneManager.getTelephonyManager(context); 325 | // SIM卡已准备好:SIM_STATE_READY=5 326 | if (tm.getSimState() == TelephonyManager.SIM_STATE_READY) { 327 | // 取得SIM卡供货商代码,判断运营商是中国移动\中国联通\中国电信 328 | // 我国为460;中国移动为00,中国联通为01,中国电信为03 329 | simOper = tm.getSimOperator(); 330 | /** 331 | * 获取网络类型 NETWORK_TYPE_CDMA 网络类型为CDMA NETWORK_TYPE_EDGE 332 | * 网络类型为EDGE NETWORK_TYPE_EVDO_0 网络类型为EVDO0 NETWORK_TYPE_EVDO_A 333 | * 网络类型为EVDOA NETWORK_TYPE_GPRS 网络类型为GPRS NETWORK_TYPE_HSDPA 334 | * 网络类型为HSDPA NETWORK_TYPE_HSPA 网络类型为HSPA NETWORK_TYPE_HSUPA 335 | * 网络类型为HSUPA NETWORK_TYPE_UMTS 网络类型为UMTS 336 | * 337 | * 在中国,联通的3G为UMTS或HSDPA,移动和联通的2G为GPRS或EGDE,电信的2G为CDMA,电信的3G为EVDO 338 | */ 339 | int type = tm.getNetworkType(); 340 | if (type == TelephonyManager.PHONE_TYPE_GSM // GSM网 341 | || type == TelephonyManager.NETWORK_TYPE_EDGE 342 | || type == TelephonyManager.NETWORK_TYPE_HSDPA) { 343 | 344 | GsmCellLocation gsm = ((GsmCellLocation) tm 345 | .getCellLocation()); 346 | if (gsm != null) { 347 | // 取得SIM卡供货商代码,判断运营商是中国移动\中国联通\中国电信 348 | // 我国为460;中国移动为00,中国联通为01,中国电信为03 349 | simOper = tm.getSimOperator(); 350 | // 基站ID 351 | cid = gsm.getCid(); 352 | // 区域码 353 | lac = gsm.getLac(); 354 | 355 | networkid = 0; 356 | } else { 357 | 358 | } 359 | } else if (type == TelephonyManager.NETWORK_TYPE_CDMA // 电信cdma网 360 | || type == TelephonyManager.NETWORK_TYPE_1xRTT 361 | || type == TelephonyManager.NETWORK_TYPE_EVDO_0 362 | || type == TelephonyManager.NETWORK_TYPE_EVDO_A) { 363 | 364 | CdmaCellLocation cdma = (CdmaCellLocation) tm 365 | .getCellLocation(); 366 | if (cdma != null) { 367 | // 运营商1 368 | String mcc = tm.getNetworkOperator().substring(0, 3); 369 | // 运营商2 370 | String mnc = String.valueOf(cdma.getSystemId()); 371 | simOper = mcc + mnc; 372 | // 基站ID 373 | cid = cdma.getBaseStationId(); 374 | // 区域码 375 | lac = cdma.getSystemId(); 376 | 377 | networkid = cdma.getNetworkId(); 378 | } else { 379 | 380 | } 381 | } 382 | } 383 | } catch (Exception e) { 384 | return ""; 385 | } 386 | return simOper + ":" + cid + ":" + lac + ":" + networkid; 387 | } 388 | 389 | } 390 | -------------------------------------------------------------------------------- /app/src/main/java/info/smemo/wechatvideorecorder/StringUtil.java: -------------------------------------------------------------------------------- 1 | package info.smemo.wechatvideorecorder; 2 | 3 | import java.io.UnsupportedEncodingException; 4 | import java.util.List; 5 | import java.util.regex.Matcher; 6 | import java.util.regex.Pattern; 7 | 8 | 9 | public class StringUtil { 10 | 11 | /** 12 | * 判断给定字符串是否空白串。 空白串是指由空格、制表符、回车符、换行符组成的字符串 若输入字符串为null或空字符串,返回true 13 | * 14 | * @param input 15 | * @return boolean 16 | */ 17 | public static boolean isEmpty(String input) { 18 | if (input == null || "".equals(input) || input.equals("null")) 19 | return true; 20 | 21 | for (int i = 0; i < input.length(); i++) { 22 | char c = input.charAt(i); 23 | if (c != ' ' && c != '\t' && c != '\r' && c != '\n') { 24 | return false; 25 | } 26 | } 27 | 28 | return true; 29 | } 30 | 31 | /** 32 | * 字符串转整数 33 | * 34 | * @param str 35 | * @param defValue 36 | * @return 37 | */ 38 | public static int toInt(String str, int defValue) { 39 | try { 40 | return Integer.parseInt(str); 41 | } catch (Exception e) { 42 | } 43 | return defValue; 44 | } 45 | 46 | /** 47 | * 对象转整数 48 | * 49 | * @param obj 50 | * @return 转换异常返回 0 51 | */ 52 | public static int toInt(Object obj) { 53 | if (obj == null) return 0; 54 | return toInt(obj.toString(), 0); 55 | } 56 | 57 | /** 58 | * 对象转整数 59 | * 60 | * @param obj 61 | * @return 转换异常返回 0 62 | */ 63 | public static long toLong(String obj) { 64 | try { 65 | return Long.parseLong(obj); 66 | } catch (Exception e) { 67 | } 68 | return 0; 69 | } 70 | 71 | /** 72 | * 字符串转布尔值 73 | * 74 | * @param b 75 | * @return 转换异常返回 false 76 | */ 77 | public static boolean toBool(String b) { 78 | try { 79 | return Boolean.parseBoolean(b); 80 | } catch (Exception e) { 81 | } 82 | return false; 83 | } 84 | 85 | /** 86 | * 判断数组是否包含某个字符串 87 | * 88 | * @param arry 89 | * @param str 90 | * @return 91 | */ 92 | public static boolean containsLikeStr(String[] arry, String str) { 93 | for (String string : arry) { 94 | if (string.contains(str.trim())) { 95 | return true; 96 | } 97 | } 98 | return false; 99 | } 100 | 101 | /** 102 | * 判断数组是否包含某个字符串 103 | * 104 | * @param arry 105 | * @param str 106 | * @return 107 | */ 108 | public static boolean containsStr(String[] arry, String str) { 109 | for (String string : arry) { 110 | if (string.equals(str.trim())) { 111 | return true; 112 | } 113 | } 114 | return false; 115 | } 116 | 117 | 118 | /** 119 | * Unicode转汉字 120 | * 121 | * @param data 122 | * @return 123 | */ 124 | public static String convertUnicode(String data) { 125 | try { 126 | return new String(data.getBytes(), "UTF-8"); 127 | } catch (UnsupportedEncodingException e) { 128 | e.printStackTrace(); 129 | } 130 | return ""; 131 | } 132 | 133 | /** 134 | * 判断list是否为空 135 | * 136 | * @param list 137 | * @return boolean 138 | */ 139 | @SuppressWarnings("rawtypes") 140 | public static boolean isEmpty(List list) { 141 | 142 | if (list == null || list.size() == 0) { 143 | return true; 144 | } else { 145 | return false; 146 | } 147 | 148 | } 149 | 150 | public static boolean containsLikeStr(List list, String str) { 151 | for (String string : list) { 152 | if (string.equals(str.trim())) { 153 | return true; 154 | } 155 | } 156 | return false; 157 | } 158 | 159 | public static String getHost(String url) { 160 | if (url == null || url.trim().equals("")) { 161 | return ""; 162 | } 163 | String host = ""; 164 | String regex = "^(https?)://[-a-zA-Z0-9.:]+[-a-zA-Z0-9]"; 165 | Pattern p = Pattern.compile(regex); 166 | Matcher matcher = p.matcher(url); 167 | if (matcher.find()) { 168 | host = matcher.group(); 169 | } 170 | return host; 171 | } 172 | } 173 | -------------------------------------------------------------------------------- /app/src/main/java/info/smemo/wechatvideorecorder/VideoRecordActivity.java: -------------------------------------------------------------------------------- 1 | package info.smemo.wechatvideorecorder; 2 | 3 | import android.app.Activity; 4 | import android.os.Bundle; 5 | import android.view.MotionEvent; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.view.animation.AlphaAnimation; 9 | import android.view.animation.Animation; 10 | import android.view.animation.AnimationSet; 11 | import android.view.animation.ScaleAnimation; 12 | import android.widget.Button; 13 | import android.widget.TextView; 14 | 15 | import java.io.File; 16 | 17 | /** 18 | * Created by suzhenpeng on 2015/6/1. 19 | */ 20 | public class VideoRecordActivity extends Activity { 21 | 22 | private VideoRecorderView recoderView; 23 | private Button videoController; 24 | private TextView message; 25 | private boolean isCancel = false; 26 | 27 | @Override 28 | protected void onCreate(Bundle savedInstanceState) { 29 | super.onCreate(savedInstanceState); 30 | 31 | setContentView(R.layout.activity_record); 32 | 33 | recoderView = (VideoRecorderView) findViewById(R.id.recoder); 34 | videoController = (Button) findViewById(R.id.videoController); 35 | message = (TextView) findViewById(R.id.message); 36 | 37 | ViewGroup.LayoutParams params = recoderView.getLayoutParams(); 38 | int[] dev = PhoneUtil.getResolution(this); 39 | params.width = dev[0]; 40 | params.height = (int) (((float) dev[0])); 41 | recoderView.setLayoutParams(params); 42 | videoController.setOnTouchListener(new VideoTouchListener()); 43 | 44 | recoderView.setRecorderListener(new VideoRecorderView.RecorderListener() { 45 | 46 | @Override 47 | public void recording(int maxtime, int nowtime) { 48 | 49 | } 50 | 51 | @Override 52 | public void recordSuccess(File videoFile) { 53 | System.out.println("recordSuccess"); 54 | if (videoFile != null) 55 | System.out.println(videoFile.getAbsolutePath()); 56 | releaseAnimations(); 57 | } 58 | 59 | @Override 60 | public void recordStop() { 61 | System.out.println("recordStop"); 62 | } 63 | 64 | @Override 65 | public void recordCancel() { 66 | System.out.println("recordCancel"); 67 | releaseAnimations(); 68 | } 69 | 70 | @Override 71 | public void recordStart() { 72 | System.out.println("recordStart"); 73 | } 74 | 75 | @Override 76 | public void videoStop() { 77 | System.out.println("videoStop"); 78 | } 79 | 80 | @Override 81 | public void videoStart() { 82 | System.out.println("videoStart"); 83 | } 84 | 85 | 86 | }); 87 | 88 | } 89 | 90 | public class VideoTouchListener implements View.OnTouchListener { 91 | 92 | @Override 93 | public boolean onTouch(View v, MotionEvent event) { 94 | 95 | 96 | switch (event.getAction()) { 97 | case MotionEvent.ACTION_DOWN: 98 | recoderView.startRecord(); 99 | isCancel = false; 100 | pressAnimations(); 101 | break; 102 | case MotionEvent.ACTION_MOVE: 103 | if (event.getX() > 0 104 | && event.getX() < videoController.getWidth() 105 | && event.getY() > 0 106 | && event.getY() < videoController.getHeight()) { 107 | showPressMessage(); 108 | isCancel = false; 109 | } else { 110 | cancelAnimations(); 111 | isCancel = true; 112 | } 113 | break; 114 | case MotionEvent.ACTION_UP: 115 | if (isCancel) { 116 | recoderView.cancelRecord(); 117 | }else{ 118 | recoderView.endRecord(); 119 | } 120 | message.setVisibility(View.GONE); 121 | releaseAnimations(); 122 | break; 123 | default: 124 | break; 125 | } 126 | return false; 127 | } 128 | } 129 | 130 | /** 131 | * 移动取消弹出动画 132 | */ 133 | public void cancelAnimations() { 134 | message.setBackgroundColor(getResources().getColor(android.R.color.holo_red_light)); 135 | message.setTextColor(getResources().getColor(android.R.color.white)); 136 | message.setText("松手取消"); 137 | } 138 | 139 | /** 140 | * 显示提示信息 141 | */ 142 | public void showPressMessage() { 143 | message.setVisibility(View.VISIBLE); 144 | message.setBackgroundColor(getResources().getColor(android.R.color.transparent)); 145 | message.setTextColor(getResources().getColor(android.R.color.holo_green_light)); 146 | message.setText("上移取消"); 147 | } 148 | 149 | 150 | /** 151 | * 按下时候动画效果 152 | */ 153 | public void pressAnimations() { 154 | AnimationSet animationSet = new AnimationSet(true); 155 | ScaleAnimation scaleAnimation = new ScaleAnimation(1, 1.5f, 156 | 1, 1.5f, 157 | Animation.RELATIVE_TO_SELF, 0.5f, 158 | Animation.RELATIVE_TO_SELF, 0.5f); 159 | scaleAnimation.setDuration(200); 160 | 161 | AlphaAnimation alphaAnimation = new AlphaAnimation(1, 0); 162 | alphaAnimation.setDuration(200); 163 | 164 | animationSet.addAnimation(scaleAnimation); 165 | animationSet.addAnimation(alphaAnimation); 166 | animationSet.setFillAfter(true); 167 | 168 | videoController.startAnimation(animationSet); 169 | } 170 | 171 | /** 172 | * 释放时候动画效果 173 | */ 174 | public void releaseAnimations() { 175 | AnimationSet animationSet = new AnimationSet(true); 176 | ScaleAnimation scaleAnimation = new ScaleAnimation(1.5f, 1f, 177 | 1.5f, 1f, 178 | Animation.RELATIVE_TO_SELF, 0.5f, 179 | Animation.RELATIVE_TO_SELF, 0.5f); 180 | scaleAnimation.setDuration(200); 181 | 182 | AlphaAnimation alphaAnimation = new AlphaAnimation(0, 1); 183 | alphaAnimation.setDuration(200); 184 | 185 | animationSet.addAnimation(scaleAnimation); 186 | animationSet.addAnimation(alphaAnimation); 187 | animationSet.setFillAfter(true); 188 | 189 | message.setVisibility(View.GONE); 190 | videoController.startAnimation(animationSet); 191 | } 192 | 193 | 194 | } 195 | -------------------------------------------------------------------------------- /app/src/main/java/info/smemo/wechatvideorecorder/VideoRecorderView.java: -------------------------------------------------------------------------------- 1 | package info.smemo.wechatvideorecorder; 2 | 3 | import android.content.Context; 4 | import android.hardware.Camera; 5 | import android.media.Image; 6 | import android.media.MediaPlayer; 7 | import android.media.MediaRecorder; 8 | import android.os.Environment; 9 | import android.os.Handler; 10 | import android.os.Message; 11 | import android.util.AttributeSet; 12 | import android.view.LayoutInflater; 13 | import android.view.SurfaceHolder; 14 | import android.view.SurfaceView; 15 | import android.view.View; 16 | import android.widget.ImageView; 17 | import android.widget.LinearLayout; 18 | import android.widget.ProgressBar; 19 | 20 | import java.io.File; 21 | import java.io.IOException; 22 | import java.util.Timer; 23 | import java.util.TimerTask; 24 | 25 | /** 26 | * Created by suzhenpeng on 2015/6/1. 27 | */ 28 | public class VideoRecorderView extends LinearLayout implements MediaRecorder.OnErrorListener { 29 | 30 | //视频展示 31 | private SurfaceView surfaceView; 32 | private SurfaceHolder surfaceHoler; 33 | 34 | private SurfaceView videoSurfaceView; 35 | private ImageView playVideo; 36 | 37 | //进度条 38 | private ProgressBar progressBar_left; 39 | private ProgressBar progressBar_right; 40 | 41 | //录制视频 42 | private MediaRecorder mediaRecorder; 43 | //摄像头 44 | private Camera camera; 45 | private Timer timer; 46 | 47 | //视频播放 48 | private MediaPlayer mediaPlayer; 49 | 50 | //时间限制 51 | private static final int recordMaxTime = 10; 52 | private int timeCount; 53 | //生成的文件 54 | private File vecordFile; 55 | 56 | private Context context; 57 | 58 | //正在录制 59 | private boolean isRecording = false; 60 | //录制成功 61 | private boolean isSuccess = false; 62 | 63 | private RecorderListener recorderListener; 64 | 65 | public VideoRecorderView(Context context) { 66 | super(context, null); 67 | this.context = context; 68 | } 69 | 70 | public VideoRecorderView(Context context, AttributeSet attrs) { 71 | super(context, attrs, 0); 72 | this.context = context; 73 | init(); 74 | } 75 | 76 | public VideoRecorderView(Context context, AttributeSet attrs, int defStyleAttr) { 77 | super(context, attrs, defStyleAttr); 78 | this.context = context; 79 | } 80 | 81 | private void init() { 82 | 83 | LayoutInflater.from(context).inflate(R.layout.ui_recorder, this); 84 | surfaceView = (SurfaceView) findViewById(R.id.surfaceview); 85 | videoSurfaceView = (SurfaceView) findViewById(R.id.playView); 86 | playVideo = (ImageView) findViewById(R.id.playVideo); 87 | 88 | progressBar_left = (ProgressBar) findViewById(R.id.progressBar_left); 89 | progressBar_right = (ProgressBar) findViewById(R.id.progressBar_right); 90 | 91 | progressBar_left.setMax(recordMaxTime * 20); 92 | progressBar_right.setMax(recordMaxTime * 20); 93 | 94 | progressBar_left.setProgress(recordMaxTime * 20); 95 | 96 | surfaceHoler = surfaceView.getHolder(); 97 | surfaceHoler.addCallback(new CustomCallBack()); 98 | surfaceHoler.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); 99 | 100 | initCamera(); 101 | 102 | playVideo.setOnClickListener(new OnClickListener() { 103 | @Override 104 | public void onClick(View v) { 105 | playVideo(); 106 | } 107 | }); 108 | } 109 | 110 | private class CustomCallBack implements SurfaceHolder.Callback { 111 | 112 | @Override 113 | public void surfaceCreated(SurfaceHolder holder) { 114 | initCamera(); 115 | } 116 | 117 | @Override 118 | public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { 119 | 120 | } 121 | 122 | @Override 123 | public void surfaceDestroyed(SurfaceHolder holder) { 124 | freeCameraResource(); 125 | } 126 | } 127 | 128 | 129 | @Override 130 | public void onError(MediaRecorder mr, int what, int extra) { 131 | try { 132 | if (mr != null) 133 | mr.reset(); 134 | } catch (Exception e) { 135 | 136 | } 137 | } 138 | 139 | /** 140 | * 初始化摄像头 141 | */ 142 | private void initCamera() { 143 | if (camera != null) 144 | freeCameraResource(); 145 | try { 146 | camera = Camera.open(); 147 | } catch (Exception e) { 148 | e.printStackTrace(); 149 | freeCameraResource(); 150 | } 151 | if (camera == null) 152 | return; 153 | 154 | camera.setDisplayOrientation(90); 155 | camera.autoFocus(null); 156 | try { 157 | camera.setPreviewDisplay(surfaceHoler); 158 | } catch (IOException e) { 159 | e.printStackTrace(); 160 | } 161 | camera.startPreview(); 162 | camera.unlock(); 163 | } 164 | 165 | /** 166 | * 初始化摄像头配置 167 | */ 168 | private void initRecord() { 169 | mediaRecorder = new MediaRecorder(); 170 | mediaRecorder.reset(); 171 | if (camera != null) 172 | mediaRecorder.setCamera(camera); 173 | 174 | mediaRecorder.setOnErrorListener(this); 175 | mediaRecorder.setPreviewDisplay(surfaceHoler.getSurface()); 176 | mediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA); 177 | mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC); 178 | 179 | 180 | mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4); 181 | mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC); 182 | mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.MPEG_4_SP); 183 | 184 | mediaRecorder.setVideoSize(352, 288); 185 | 186 | // mediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH)); 187 | mediaRecorder.setVideoFrameRate(16); 188 | mediaRecorder.setVideoEncodingBitRate(1 * 1024 * 512); 189 | mediaRecorder.setOrientationHint(90); 190 | 191 | mediaRecorder.setMaxDuration(recordMaxTime * 1000); 192 | mediaRecorder.setOutputFile(vecordFile.getAbsolutePath()); 193 | } 194 | 195 | private void prepareRecord() { 196 | try { 197 | mediaRecorder.prepare(); 198 | mediaRecorder.start(); 199 | } catch (IOException e) { 200 | e.printStackTrace(); 201 | } 202 | } 203 | 204 | /** 205 | * 开始录制 206 | */ 207 | public void startRecord() { 208 | 209 | //录制中 210 | if (isRecording) 211 | return; 212 | //创建文件 213 | createRecordDir(); 214 | 215 | initCamera(); 216 | 217 | videoSurfaceView.setVisibility(View.GONE); 218 | playVideo.setVisibility(View.GONE); 219 | surfaceView.setVisibility(View.VISIBLE); 220 | 221 | //初始化控件 222 | initRecord(); 223 | prepareRecord(); 224 | isRecording = true; 225 | if (recorderListener != null) 226 | recorderListener.recordStart(); 227 | //10秒自动化结束 228 | timeCount = 0; 229 | timer = new Timer(); 230 | timer.schedule(new TimerTask() { 231 | @Override 232 | public void run() { 233 | timeCount++; 234 | progressBar_left.setProgress(timeCount); 235 | progressBar_right.setProgress(recordMaxTime * 20 - timeCount); 236 | if (recorderListener != null) 237 | recorderListener.recording(recordMaxTime * 1000, timeCount * 50); 238 | if (timeCount == recordMaxTime * 20) { 239 | Message message = new Message(); 240 | message.what = 1; 241 | handler.sendMessage(message); 242 | } 243 | } 244 | }, 0, 50); 245 | } 246 | 247 | Handler handler = new Handler() { 248 | @Override 249 | public void handleMessage(Message msg) { 250 | super.handleMessage(msg); 251 | if (msg.what == 1) { 252 | endRecord(); 253 | } 254 | } 255 | }; 256 | 257 | /** 258 | * 停止录制 259 | */ 260 | public void endRecord() { 261 | if (!isRecording) 262 | return; 263 | isRecording = false; 264 | if (recorderListener != null) { 265 | recorderListener.recordStop(); 266 | recorderListener.recordSuccess(vecordFile); 267 | } 268 | stopRecord(); 269 | releaseRecord(); 270 | freeCameraResource(); 271 | videoSurfaceView.setVisibility(View.VISIBLE); 272 | playVideo.setVisibility(View.VISIBLE); 273 | } 274 | 275 | /** 276 | * 取消录制 277 | */ 278 | public void cancelRecord() { 279 | videoSurfaceView.setVisibility(View.GONE); 280 | playVideo.setVisibility(View.GONE); 281 | surfaceView.setVisibility(View.VISIBLE); 282 | if (!isRecording) 283 | return; 284 | isRecording = false; 285 | stopRecord(); 286 | releaseRecord(); 287 | freeCameraResource(); 288 | isRecording = false; 289 | if (vecordFile.exists()) 290 | vecordFile.delete(); 291 | if (recorderListener != null) 292 | recorderListener.recordCancel(); 293 | initCamera(); 294 | } 295 | 296 | /** 297 | * 停止录制 298 | */ 299 | private void stopRecord() { 300 | progressBar_left.setProgress(recordMaxTime * 20); 301 | progressBar_right.setProgress(0); 302 | 303 | if (timer != null) 304 | timer.cancel(); 305 | if (mediaRecorder != null) { 306 | // 设置后不会崩 307 | mediaRecorder.setOnErrorListener(null); 308 | mediaRecorder.setPreviewDisplay(null); 309 | try { 310 | mediaRecorder.stop(); 311 | } catch (IllegalStateException e) { 312 | e.printStackTrace(); 313 | } catch (RuntimeException e) { 314 | e.printStackTrace(); 315 | } catch (Exception e) { 316 | e.printStackTrace(); 317 | } 318 | } 319 | } 320 | 321 | 322 | public void destoryMediaPlayer() { 323 | if (mediaPlayer == null) 324 | return; 325 | mediaPlayer.setDisplay(null); 326 | mediaPlayer.reset(); 327 | mediaPlayer.release(); 328 | mediaPlayer = null; 329 | } 330 | 331 | /** 332 | * 播放视频 333 | */ 334 | public void playVideo() { 335 | surfaceView.setVisibility(View.GONE); 336 | videoSurfaceView.setVisibility(View.VISIBLE); 337 | playVideo.setVisibility(View.GONE); 338 | mediaPlayer = new MediaPlayer(); 339 | try { 340 | mediaPlayer.reset(); 341 | mediaPlayer.setDataSource(vecordFile.getAbsolutePath()); 342 | mediaPlayer.setDisplay(videoSurfaceView.getHolder()); 343 | mediaPlayer.prepare();//缓冲 344 | mediaPlayer.start(); 345 | } catch (Exception e) { 346 | e.printStackTrace(); 347 | } 348 | if (recorderListener != null) 349 | recorderListener.videoStart(); 350 | mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { 351 | @Override 352 | public void onCompletion(MediaPlayer mp) { 353 | if (recorderListener != null) 354 | recorderListener.videoStop(); 355 | playVideo.setVisibility(View.VISIBLE); 356 | } 357 | }); 358 | } 359 | 360 | public RecorderListener getRecorderListener() { 361 | return recorderListener; 362 | } 363 | 364 | public void setRecorderListener(RecorderListener recorderListener) { 365 | this.recorderListener = recorderListener; 366 | } 367 | 368 | public SurfaceView getSurfaceView() { 369 | 370 | return surfaceView; 371 | } 372 | 373 | public void setSurfaceView(SurfaceView surfaceView) { 374 | this.surfaceView = surfaceView; 375 | } 376 | 377 | public MediaPlayer getMediaPlayer() { 378 | return mediaPlayer; 379 | } 380 | 381 | public interface RecorderListener { 382 | 383 | public void recording(int maxtime, int nowtime); 384 | 385 | public void recordSuccess(File videoFile); 386 | 387 | public void recordStop(); 388 | 389 | public void recordCancel(); 390 | 391 | public void recordStart(); 392 | 393 | public void videoStop(); 394 | 395 | public void videoStart(); 396 | } 397 | 398 | 399 | /** 400 | * 创建视频文件 401 | */ 402 | private void createRecordDir() { 403 | File sampleDir = new File(Environment.getExternalStorageDirectory() + File.separator + "WeChatVideoRecorder/"); 404 | if (!sampleDir.exists()) { 405 | sampleDir.mkdirs(); 406 | } 407 | File vecordDir = sampleDir; 408 | // 创建文件 409 | try { 410 | vecordFile = File.createTempFile("recording", ".mp4", vecordDir);//mp4格式 411 | } catch (IOException e) { 412 | } 413 | } 414 | 415 | /** 416 | * 释放资源 417 | */ 418 | private void releaseRecord() { 419 | if (mediaRecorder != null) { 420 | mediaRecorder.setOnErrorListener(null); 421 | try { 422 | mediaRecorder.release(); 423 | } catch (IllegalStateException e) { 424 | e.printStackTrace(); 425 | } catch (Exception e) { 426 | e.printStackTrace(); 427 | } 428 | } 429 | mediaRecorder = null; 430 | } 431 | 432 | /** 433 | * 释放摄像头资源 434 | */ 435 | private void freeCameraResource() { 436 | if (null != camera) { 437 | camera.setPreviewCallback(null); 438 | camera.stopPreview(); 439 | camera.lock(); 440 | camera.release(); 441 | camera = null; 442 | } 443 | } 444 | } 445 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_play_action_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/szpnygo/WeChatVideoRecorder/fe00ffd9282ed7dafd72ee73de31033e0ecb1353/app/src/main/res/drawable-xxhdpi/ic_play_action_normal.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_play_action_pressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/szpnygo/WeChatVideoRecorder/fe00ffd9282ed7dafd72ee73de31033e0ecb1353/app/src/main/res/drawable-xxhdpi/ic_play_action_pressed.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/video_bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/szpnygo/WeChatVideoRecorder/fe00ffd9282ed7dafd72ee73de31033e0ecb1353/app/src/main/res/drawable-xxhdpi/video_bg.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/video_button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/szpnygo/WeChatVideoRecorder/fe00ffd9282ed7dafd72ee73de31033e0ecb1353/app/src/main/res/drawable-xxhdpi/video_button.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/video_ok.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/szpnygo/WeChatVideoRecorder/fe00ffd9282ed7dafd72ee73de31033e0ecb1353/app/src/main/res/drawable-xxhdpi/video_ok.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_play_action.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/video_progress_color_left.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/video_progress_color_right.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_record.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 11 | 12 | 22 | 23 | 28 | 29 | 30 | 31 | 34 | 35 | 36 | 41 | 42 | 55 | 56 | 57 | 58 | 59 | 60 | 65 | 66 |