android media.media.projection

NashLegend 的BLOG
用户名:NashLegend
文章数:15
访问量:22074
注册日期:
阅读量:5863
阅读量:12276
阅读量:371985
阅读量:1065951
51CTO推荐博文
Android 5.0 API变化译自&&―― By&Sample示例在这里找:原译文在我的github上:前排渣翻译预警,如果你能提供更好更专业的翻译或者提出修改意见就好了……API Level: 21Android 5.0 () 为用户和开发人员提供了一些新特性,这篇文章将重点介绍一些值得注意的新增API。如果你已经发布了一款app,请查看这里&&以适配你的app. 在Android5.0上,即使你没有使用最新API或者新功能,这些新的系统行为仍可能会影响你的app。如果想看一些新平台的更高级的特性,请看开始开发要为Android 5.0开发app,请先使用SDK Mnager下载最新的SDK和系统镜像。升级你的target API为使得你的app在Android获得更好的表现,请将你的targetSdkVersion设置成21。调用最新的Android 5.0 API的时候要注意在调用前判断系统版本号以兼容之前的系统版本。不能使用低于minSdkVersion的API。详见欲知更多有关API级别的事儿,看这里:用户界面Material design 支持Android 5.0 新增了material design样式的支持. 你可以通过material design创建具有自然的动态效果和过渡风格的app. 系统支持包括以下方面:系统自带Material design主题组件阴影RecyclerView组件以取代ListViewDrawable动画和样式效果。(这里应该是指Ripple Drawable之类)(Drawable animation and styling effects)Material design风格的动画和activity过渡效果基于组件状态的Animator。(Animators for view properties based on the state of the view)可定制的UI组件和工具栏(这里指的应该是ToolBar)基于XML的矢量动画和图形(Animated and non-animated drawables)欲知更多有关Material Design的事儿,看。以及我翻译的下面两篇:。。“最近运行”界面上的多开的文档和activity(相当于MFC等的多文档)以前的版本中,“”界面对于一个app来说只能显示用户最近交互过的一个task。现在你的应用可以打开更多task以同时打开不同的文档。这种新的多任务特性可以让用户在最近运行界面中快速在activity们和打开的文档们之间任意切换。有可能使用这种并发任务的情景示例:浏览器标签多开、看比赛多开、生产力工具(比如Word、PPT等)文档多开、多窗口与多个妹子聊天等等。你的app可以通过来管理这些task。要让系统把你的activity当成一个新的task,在startActivity()的时候使用,你也可以在manifest文件中把activity的documentLaunchMode属性设置成"intoExisting"&或者&"always"来实现这一点。为了避免“最近运行”界面太多太乱,你可以设置你的app可以显示在此界面上的最大任务数量――设置manifest文件中 的属性android:maxRecents,目前的最大数量是每个用户50个,RAM较小的手机则为25个。最近运行界面上的task可以设置为重启时常驻(persist across reboots),可以设置属性以控制常驻行为。你也可以通过方法修改activity在最近运行界面上的颜色、标签和图标等可见元素。WebView 更新Android 5.0的WebView升级到了Chromium M37,修复了诸多bug以及带来了安全和稳定性的加强,默认的user-agent也已经升级到了37.0.0.0。新的WebView引入了类,可以允许你的app通过类似赋予WebView摄像头和麦克风的权限――当然前提是你的app也有相应的权限。使用最新的方法,你可以通过一个input选择设备里的图片和文件了。此外,新的WebView还带来了对WebAudio,WebGL,WebRTC的支持。欲知更多WebView的新特性,请看。屏幕捕获和分享Android 5.0新增&API以让你拥有捕获和屏幕分享功能。举个例子,如果你要在视频会议app中添加屏幕分享功能的话,就可以使用这个功能。新的&&方法 允许你的app将主屏幕内容(the default display)捕获到一个Surface对象上,这样你的app就可以通过网络对此进行分享。这个API只允许捕获非敏感屏幕内容,不能捕获声音。要进行屏幕捕获,你的app必须要先发起一个对话框请求用户同意,此请求通过发送&方法产生的Intent实现。你可以查看示例项目的MediaProjectionDemo来学习如何使用新的API。通知锁屏通知从Android 5.0开始可以在锁屏界面上显示通知。用户可以通过设置选择是否允许敏感通知内容显示在安全锁屏界面(secure lock screen)上。你的应用可以控制通知内容的具体显示级别,通过调用方法传入下面值中的一个:VISIBILITY_PRIVATE: 显示基本信息,比如说icon,但是隐藏具体内容。VISIBILITY_PUBLIC: 显示通知的所有内容.VISIBILITY_SECRET: 不显示任何东西,icon也不显示.如果你设置的是VISIBILITY_PRIVATE,你可以设置显示敏感内容的替代信息,比如“收到了3条QQ消息”,但是不显示具体消息的联系人。要提供这种显示,首先用Notification.Builder创建一个替代通知。当创建private通知的时候,通过&方法将这个替代通知关联到这个隐私通知上。Notifications 元数据Android 5.0通过关联在你的通知上的元数据对通知进行智能排序。你可以通过Notification.Builder的下面这些方法设置这些元数据:: 告诉系统当设备处于优先模式(比如这个通知表明来电、即时消息或者闹钟)时如何处理通知。: 标记此通知的重要程度――是否比普通通知要高或者低。拥有&或者&级别的通知在有声音或者振动的情况下,会弹出一个浮动窗口。: 允许你添加一个或者多个与此通知相关联的人。这样系统可以根据不同的人把通知分开,并按人物重要性排序。图形对OpenGL ES 3.1的支持Android 5.0为OpenGL ES 3.1增加java接口和native支持。3.1重要的新增功能包括:计算着色器(Compute Shaders)独立的着色器对象间接呼叫指令多重采样和模版纹理着色语言改进高级混合模式和调试扩展。对OpenGL ES 2.0 和 3.0和后向兼容性OpenGL ES 3.1 的java接口是。使用OpenGL ES 3.1的时候,请在manifest里面使用标签及android:glEsVersion属性声明之,例如:&manifest&
&&&&&uses-feature&android:glEsVersion="0x"&/&
&/manifest&欲知更多OpenGL ES的信息,包括设备对OpenGL支持的版本,请看。Android 扩展包除了OpenGL ES 3.1,这个版本还提供了拥有java接口和native支持的扩展包以提供高级图形功能。这个扩展包作为一个独立的包发布扩展包支持:这块儿不懂Guaranteed fragment shader support for shader storage buffers, images, and atomics (Fragment shader support is optional in OpenGL ES 3.1.) Tessellation and geometry shaders ASTC (LDR) texture compression format Per-sample interpolation and shading Different blend modes for each color attachment in a frame bufferThe Java interface for the extension pack is provided with GLES31Ext. In your app manifest, you can declare that your app must be installed only on devices that support the extension pack. For example:&manifest&
&&&&&uses-feature&android:name=“android.hardware.opengles.aep”
&&&&&&&&android:required="true"&/&
&/manifest&媒体高级相机功能的相机APIAndroid 5.0引入了新的&API以帮助fine-grain照片捕捉和图像处理,你可以编程的方式通过调用&获取系统的可用相机设备列表并通过。你可以通过&&方法指定其中一个相机设备。要捕捉图像,创建一个并将捕获到的图像绘制到一个Surface对象上。 CameraCaptureSession可设置为单拍或者一次性连拍多张(take single shots or multiple images in a burst)。需要继承类并设置到图像捕获请求里以获得图像捕获完成事件。当系统完成图像捕获的时候,CameraCaptureSession.CaptureCallback将接到一个回调,返回给你一个包含图像元数据的&。类可以让你的app检查此设备的相机支持哪些特性。此对象的属性表示相机功能级别。所有的设备至少可达到级别的硬件支持,此级别功能大致相当于已弃用的&API(注:此API在API21开始弃用)。达到级别硬件支持的设备可以手动控制图像的捕捉和后期处理以及以高帧频捕获高分辨率的图像。要查看如何使用最新的camera2 API,请查看SDK示例中的Camera2Basic&和&Camera2Video音频回放此版本包含的以下变化:你的app现在可以用浮点格式()提供音频数据。可以获得更大的动态范围,more consistent precision和greater headroom。浮点运算在中间值计算(intermediate calculation)的时候尤其有用。Playback endpoints use integer format for audio data, and with lower bit depth. (In Android 5.0, portions of the internal pipeline are not yet floating point.)你现在可以ByteBuffer方式提供音频数据,就像提供给的数据一样。模式可以帮助某些app简化缓冲和多线程工作(simplify buffering and multithreading)。媒体播放控制使用新的通知和媒体API以确保系统UI知道你的媒体播放情况并提取和显示专辑信息。使用新的&和类可使得通过UI和service控制播放变得更加简单。新的MediaSession类取代了已弃用的,它提供一套回调方法以处理各种播放行为(差不多这么翻译吧,无非是快进快退暂停以及其他控制等等)&(transport controls and media buttons)。如果你的app提供媒体播放功能并且运行在Android TV或者Wear平台上,也可以通过MediaSession类使用相同的回调方法处理播放行为(transport controls)。现在你可以使用类创建自己的媒体控制器app。这个类提供了一个线程安全的方式以在你的UI线程上监控和控制媒体的播放行为。创建控制器的时候,指定一个对象以便与给定的MediaSession交互。通过使用方法,你可以传达诸如&,&,&, 和&命令以控制MediaSession上的媒体播放。你也可以注册一个回调对象以监听session上的元数据和状态变化(metadata and state changes)。此外,你还可以通过最新的类创建rich notification以控制mediasession播放。媒体浏览Android 5.0引入了新的&API,你的app可以使用此api浏览其他app的媒体库。继承类以对外暴露你的app的媒体内容。你继承的MediaBrowserService应该提供MediaSession.Token的接入口以便其他应用可以通过它播放你提供的媒体内容。若要与媒体浏览服务交互,请使用类。创建MediaBrowser实例时,请为MediaSession指定一个组件名。通过这个MediaBrowser实例,你的app可以连接到关联的service并获得一个暴露出来的MediaSession.Token对象。存储目录选择Android 5.0扩展了存储框架(Storage Access Framework),用户可以借此将一个文件夹(包括其子文件和文件夹)的读写权限赋予一个app。要选择一个文件夹,请发出一条&intent 即可。系统会列出所有支持文件夹选择的来让用户浏览并选择一个文件夹,返回值是选中的文件夹的URI。然后你就可以使用&、&&和&&浏览此文件夹的子目录了。新的&&方法使得你可以在上面选择的文件夹及其子文件夹下面创建新文档或者文件夹。要操作已经存在的文件,请使用&&和&. 调用这此方法之前先检查&&以确定provider对这些方法是否。分别是:,,,,)。如果你实现了一个并且想要支持子目录选择,请实现方法并将放到里。Android 5.0同时也引入了新的共享存储区上的package-specific目录,你可以在为里存储媒体文件,这些媒体文件可以被包含进里,新的&方法返回你的app在所有共享存储设备上的媒体存储目录。像一样不需要特殊权限。系统会定时扫描这些文件夹中的媒体内容,当然你也可以使用自行扫描新内容。(大哥们不要把缓存的图片放这儿啊,好想把那些将缓存图片直接放到sd卡某个目录下的人拉出来打一顿)无线连接多网络连接(Multiple network connections)Android 5.0支持新的多网络连接API以使你的app可以根据特定功能(with specific capabilities)动态扫描可用的网络并建立连接。当你的app需要指定网络――SUPL(无线位置服务), 彩信或者运营商计费网络――才能用或者要通过一个特定的协议才能传输你的数据的时候,这个功能就派上用场了。你的app动态选择并连接一个网络连接的步骤如下:新建一个.使用&类创建一个对象并指定你的app需要的网络特性和传输类型。要扫描合适的网络,请调用&或者&, 并将NetworkRequest对象和一个作为参数传过去。如果你要在合适的网络被扫描到之后就切换到这个网络,请调用用&&方法 如果仅仅接收扫描结果而不切换网络的话,请使用&方法. 当系统探测到一个合适的网络时连接到这个网络并调用方法。你可以使用这个方法传进来的对象得到这个网络更多的信息或者使用此网络。低功耗蓝牙(表示不懂……)Android 4.3引入了对Bluetooth Low Energy (Bluetooth LE)的平台支持in the central role(咋理解)。从Android 5.0开始,Android设备可以像低功耗蓝牙外设一样了。应用可以使用些功能使得附近的设备探测到你的存在。比如说,你可以创建一个计步器应用或者健康状况监视应用并与另外一个低功耗蓝牙外设建立数据连接。使用新的&API,你的app可以广播广告(broadcast advertisements)、扫描响应(scan for responses)并与附近的低功耗蓝牙设备连接。要使用新的广播和扫描特性,请在manifest文件中添加权限。当用户下载或者更新你的app时,会被请求允许这些权限。要开始Bluetooth LE advertising以便别的设备可以发现你的app,请调用将一个作为参数传进去。这个callback对象会接收advertising功能或者失败的消息。Android 5.0 引入了,这样你的app就可以只搜索你需要的特定类型的设备。调用方法并传递进一个filter列表以扫描低功耗蓝牙设备――你必须提供一个以在Bluetooth LE advertisement被发现后可以报告。(............)NFC增强Android 5.0对NFC进行了以下增强以使其得以更广泛和灵活的应用:Android Beam 可以在分享按钮中使用了。你的应用可以通过调用Android Beam以分享数据。避免了用户必须自己手动操作设备以来分享数据的麻烦。你现在可以使用方法创建包含UTF-8文本格式数据的NDEF记录。如果你在开发一款支付类应用,你现在可以对过调用以动态地注册一个NFC应用ID(AID)。你也可以使用方法用于在某个特定的acitivy处于前台时指定一个偏好的Card Emulation服务。Project Volta除了新特性之外(?),Android 5.0还重点突出了对电池寿命的提升(emphasizes improvements in battery life)。使用新的API和工具可以查看并优化你的app的电量使用。Scheduling jobsAndroid 5.0提供一个新的&API以让你通过使系统推迟一些时间或者在特定条件下(比如充电中)异步执行某些任务以优化电池寿命。在下面情况下这很有用。应用有可延后执行的后台任务。应用有你想在充电时才执行的任务。应用有需要网络或者WIFI才能执行的任务。应用有一些要定期统一执行(run as a batch on a regular schedule)的任务。一批任务(A unit of work)同一个对象封装,这个对象指定了任务如何安排。使用类来设置如何安排这些任务的运行时刻表,你可以安排任务在正面情况下运行,比如:设备充电时开始执行。设备连接到非计费网络时开始执行。设置空闲时开始执行。在某个deadline前或者某个delay后结束执行。举例,如果你想在设备连接到非计费网络时执行,可以这样做:JobInfo&uploadTask&=&new&JobInfo.Builder(mJobId,
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&mServiceComponent&/*&JobService&component&*/)
&&&&&&&&.setRequiredNetworkCapabilities(JobInfo.NetworkType.UNMETERED)
&&&&&&&&.build();
JobScheduler&jobScheduler&=
&&&&&&&&(JobScheduler)&context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
jobScheduler.schedule(uploadTask);如果设备有一个稳定的电源(进入充电状态超过两分钟并且电量处于),系统就会执行被安排好的任务,即使该任务的deadline还没有过期(???even if the job’s deadline has not expired)。要查看如何使用JobScheduler API,请查看Sample中的JobSchedulerSample。电量使用开发工具新的dumpsys batterystats命令可以返回你感兴趣的按唯一的UID组织的电量使用数据。数据包括以下几方面:电池相关事件历史。设备的全局数据。每个UID和系统组件的粗略的电量使用。Per-app mobile ms per packet系统UID总数据。应用UID总数据。使用--help可以学习更多的参数选项以输出你想要的数据。比如,要输出上次充电后某个指定app的电量使用数据,执行如下命令:$&adb&shell&dumpsys&batterystats&--charged&&package-name&你可以对上面的命令的输出数据使用工具来生成HTML页面以方便查看。Android在办公和教育中的应用(不知所云,一片胡扯,译者处于昏迷状态)Managed provisioningAndroid 5.0 为在办公环境中运行的app提供了新的功能。如果用户已经在设备上有了一个个人账户,设备管理员可以启动一个管理配置进程(managed provisioning process)以再添加一个共存但是相互独立的profile。受管理的profiles关联的app与非受管理的app并列出现在Launcher、最近任务和通知里面。要启动管理配置进程,发起一个&Intent。如果调用成功的话,系统回调。然后你可以调用来启动这个受管理的profile。默认情况下,在受管理的profile里面只有很少的app可用。你可以在受管理profile里面调用来使其他app在包含进profile中。如果你在开发一款Launcher程序,可以使用新的类来获取可展示到Launcher上的的activity列表――当然只能是属于当前用户和相关的受管理的profiles的。你的Launcher可以通过加入一个工作标志来使得使受管理的app突出显示出来,通过方法可以取得这种带标志的图标。查看Sample中的BasicManagedProfile来学习如何使用这些新功能。设备所有者(Device owner)Android 5.0 引入了可以部署设备所有者app的能力,设备所有者是一个拥有创建和删除子用户以及配置全局设置的特殊类型的(specialized type)设备管理员。你的所有者应用可以使用里面的方法的对设备配置、安全策略的应用进行细粒度的控制(take fine-grain control)。一个设备在同一时间只能有一个活动的设备所有者。要部署并激活设备所有者,在设备的unprovisioned状态下,进行从一个编程应用(programming app)到设备NFC数据传输。传输的数据和上面刚刚提到的provisioning intent中的数据相同。屏幕固定Android 5.0 引入了新的屏幕固定API,可以让用户暂时限制在一个任务中无法离开,此时也不会被通知所干扰。如果你正在开发一款教育应用以在Android支持高风险的评估要求或者目的单一的或者Kiosk应用程序(an education app to support high stakes assessment requirements on Android, or a single-purpose or kiosk application――这啥意思,口吐白沫中)的时候,你就可以考虑使用这个API。一旦你的app启动了屏幕固定,用户就将看不到通知、打开其他app或者返回桌面,直到退出这种模式。有两种方式启动屏幕固定:手动固定:用户可以拖动开启屏幕固定。设置&安全&屏幕固定,然后选择在最近任务界面选择在固定的任务。编程固定:要通过编码实现屏幕固定,在你的app中调用方法。如果请求的app不是设备所有者(device owner),用户会被弹出一个询问提示。设备所有者可以调用方法以使得某个app可以不经过用户确认就进步屏幕固定状态。任务锁定后,会:状态栏变空,用户通知和状态信息被隐藏。主屏幕和最近任务按钮被隐藏。其他app打不开新的activity。只要不开启新的task,当前app可以打开新的activity。如果屏幕固定是由设备所有者启动,用户仍旧会锁定在你的app下直到调用了。如果屏幕固定由非设备所有者启动或者由用户手动启动,用户可以通过同时按住返回的最近任务按钮退出(the user can exit by holding both the Back and Recent buttons)打印框架以bitmap渲染PDF现在可以用新的类将PDF页面渲染成bitmap来渲染。必须指定一个可搜索(内容可以随机访问)的,系统会在它上面写入可打印数据。通过调用方法,你的app可以得到一个待渲染页面,然后调用以将打开的渲染到一个bitmap上。如果你想只转换此文档的一部分的话,要传入额外的一些参数。要查看如何使用新的API,请查看Sample里面的PdfRendererBasic。系统应用使用数据现在你可以使用&API获取Android设备的app使用历史。这个API提供了比已经弃用的方法更详细的使用数据。要使用这个API,首先要在manifest中添加android.permission.PACKAGE_USAGE_STATS权限,用户可以通过Settings & Security & Apps赋予此app的读取app使用数据的权限.系统按应用分别收集使用数据,并且按天、周、月、年整合数据。系统保存数据的最长时间如下:Daily data: 7天Weekly data: 4周Monthly data: 6个月Yearly data: 2年对于每个应用,系统记录如下数据:应用上次使用时间。对应时间段内应用前台运行总时间(by day, week, month, or year)。一个组件(按包名和activity名区分)在一天内被移动到前台或者后台的Timestamp capturing。设备设置改变(比如屏幕方向改变)的Timestamp capturing。测试 & 辅助功能测试和可访问性改进Android 5.0为测试和可访问性增加如下支持:新的和方法可以捕获窗口动画和内容的帧数据。这些方法使你可以编写instrumentation tests以评估app是否流畅。新的方法让你可以在instrumentation test中执行shell命令。类似于执行 adb shell,这样你可以使用一些shell工具比如dumpsys, am, content&和pm.使用accessibility APIs(比如)的Accessibility Service和测试工具现在可以取得屏幕上能够进行可见交互的窗口的详细信息。要获得对象列表,请调用&方法。新的类让你可以在上执行标准的或者自定义的动作。新的&类取代了AccessibilityNodeInfo中的早期action API。Android 5.0使你的app可以对文字转语音(text-to-speech synthesis)进行更细粒度的控制。有了新的Voice类,你的App可以通过指定地区, 质量和延迟率来设置声音,也可以使用文字转语音引擎相关的特定特性(text-to-speech engine-specific parameters)。IME更容易地切换输入语言这块不翻译了,标题说的很明确了,但是输入法右下角那个切换按钮总是误触好蛋疼啊~摔~Manifest 声明Declarable required features下面的一些特性已经开始在&uses-feature&中支持,所以你可以确认你的app是否安装在支持你所需特性的设备上。FEATURE_AUDIO_OUTPUTFEATURE_CAMERA_CAPABILITY_MANUAL_POST_PROCESSINGFEATURE_CAMERA_CAPABILITY_MANUAL_SENSORFEATURE_CAMERA_CAPABILITY_RAWFEATURE_CAMERA_LEVEL_FULLFEATURE_GAMEPADFEATURE_LIVE_TVFEATURE_MANAGED_USERSFEATURE_LEANBACKFEATURE_OPENGLES_EXTENSION_PACKFEATURE_SECURELY_REMOVES_USERSFEATURE_SENSOR_AMBIENT_TEMPERATUREFEATURE_SENSOR_HEART_RATE_ECGFEATURE_SENSOR_RELATIVE_HUMIDITYFEATURE_VERIFIED_BOOTFEATURE_WEBVIEWUser permissions现在&uses-permission&已经支持下面的权限,如果你需要的话就加上它吧。BIND_DREAM_SERVICE: 如果目标API是21或更高,&服务需要使用这个权限。
了这篇文章
类别:┆阅读(0)┆评论(0)Java Code Example android.media.projection.MediaProjection
Java Code Examples for android.media.projection.MediaProjection
The following are top voted examples for showing how to use
android.media.projection.MediaProjection. These examples are extracted from open source projects.
You can vote up the examples you like and your votes will be used in our system to product
more good examples.
+ Save this class to your library
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
String ip = mReceiverIpEditText.getText().toString();
final SharedPreferences sharedPreferences = getSharedPreferences(PREF_NAME, 0);
final SharedPreferences.Editor edit = sharedPreferences.edit();
edit.putString(RECEIVER_IP_KEY,ip);
if(resultCode == RESULT_OK && requestCode==GET_MEDIA_PROJECTION_CODE){
@SuppressWarnings(&ResourceType&) MediaProjectionManager mediaProjectionManager = (MediaProjectionManager) getSystemService(Context.MEDIA_PROJECTION_SERVICE);
final MediaProjection mediaProjection = mediaProjectionManager.getMediaProjection(resultCode, data);
mEncoderAsyncTask = new EncoderAsyncTask(this, mediaProjection, mMediaCodecFactory);
mEncoderAsyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
mSenderAsyncTask = new SenderAsyncTask(ip);
mSenderAsyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
} catch (IOException e) {
mStartButton.setEnabled(false);
mStartButton.setText(getString(R.string.mediacodec_error));
e.printStackTrace();
EncoderAsyncTask(MediaCodecListener listener, MediaProjection projection, MediaCodecFactory factory) throws IOException {
mListener =
mEncoder =
factory.createVideoEncoder();
Surface surface = mEncoder.createInputSurface();
mEncoder.start();
mVirtualDisplay = projection.createVirtualDisplay(LOG_TAG, factory.getWidth(), factory.getHeight(), DisplayMetrics.DENSITY_MEDIUM, 0, surface, null, null);
public MediaScreenEncoder(final MediaMuxerWrapper muxer, final MediaEncoderListener listener,
final MediaProjection projection, final int width, final int height, final int density) {
super(muxer, listener, width, height);
mMediaProjection =
mDensity =
final HandlerThread thread = new HandlerThread(TAG);
thread.start();
mHandler = new Handler(thread.getLooper());
* start screen recording as .mp4 file
* @param intent
private void startScreenRecord(final Intent intent) {
if (DEBUG) Log.v(TAG, &startScreenRecord:sMuxer=& + sMuxer);
synchronized (sSync) {
if (sMuxer == null) {
final int resultCode = intent.getIntExtra(EXTRA_RESULT_CODE, 0);
// get MediaProjection
final MediaProjection projection = mMediaProjectionManager.getMediaProjection(resultCode, intent);
if (projection != null) {
final DisplayMetrics metrics = getResources().getDisplayMetrics();
final int density = metrics.densityD
if (DEBUG) Log.v(TAG, &startRecording:&);
sMuxer = new MediaMuxerWrapper(&.mp4&); // if you record audio only, &.m4a& is also OK.
if (true) {
// for screen capturing
new MediaScreenEncoder(sMuxer, mMediaEncoderListener,
projection, metrics.widthPixels, metrics.heightPixels, density);
if (true) {
// for audio capturing
new MediaAudioEncoder(sMuxer, mMediaEncoderListener);
sMuxer.prepare();
sMuxer.startRecording();
} catch (final IOException e) {
Log.e(TAG, &startScreenRecord:&, e);
public VirtualDisplay createVirtualDisplay(Context context, MediaProjection projection,
String name, int width, int height, int densityDpi, Surface surface, int flags,
VirtualDisplay.Callback callback, Handler handler) {
if (TextUtils.isEmpty(name)) {
throw new IllegalArgumentException(&name must be non-null and non-empty&);
if (width &= 0 || height &= 0 || densityDpi &= 0) {
throw new IllegalArgumentException(&width, height, and densityDpi must be &
+ &greater than 0&);
VirtualDisplayCallback callbackWrapper = new VirtualDisplayCallback(callback, handler);
IMediaProjection projectionToken = projection != null ? projection.getProjection() :
int displayId;
displayId = mDm.createVirtualDisplay(callbackWrapper, projectionToken,
context.getPackageName(), name, width, height, densityDpi, surface, flags);
} catch (RemoteException ex) {
Log.e(TAG, &Could not create virtual display: & + name, ex);
if (displayId & 0) {
Log.e(TAG, &Could not create virtual display: & + name);
Display display = getRealDisplay(displayId);
if (display == null) {
Log.wtf(TAG, &Could not obtain display info for newly created &
+ &virtual display: & + name);
mDm.releaseVirtualDisplay(callbackWrapper);
} catch (RemoteException ex) {
return new VirtualDisplay(this, display, callbackWrapper, surface);
@TargetApi(LOLLIPOP) private void captureNativeScreenshot(final MediaProjection projection) {
capturingStart();
// Wait for the next frame to be sure our progress bars are hidden.
post(new Runnable() {
@Override public void run() {
DisplayMetrics displayMetrics = new DisplayMetrics();
windowManager.getDefaultDisplay().getRealMetrics(displayMetrics);
final int width = displayMetrics.widthP
final int height = displayMetrics.heightP
ImageReader imageReader = ImageReader.newInstance(width, height, PixelFormat.RGBX_8888, 2);
Surface surface = imageReader.getSurface();
final VirtualDisplay display =
projection.createVirtualDisplay(&telescope&, width, height, displayMetrics.densityDpi,
DisplayManager.VIRTUAL_DISPLAY_FLAG_PRESENTATION, surface, null, null);
imageReader.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() {
@Override public void onImageAvailable(ImageReader reader) {
Image image =
Bitmap bitmap =
Bitmap croppedBitmap =
FileOutputStream out =
image = reader.acquireLatestImage();
post(new Runnable() {
@Override public void run() {
capturingEnd();
if (image == null) {
Image.Plane[] planes = image.getPlanes();
ByteBuffer buffer = planes[0].getBuffer();
int pixelStride = planes[0].getPixelStride();
int rowStride = planes[0].getRowStride();
int rowPadding = rowStride - pixelStride *
bitmap = Bitmap.createBitmap(width + rowPadding / pixelStride, height,
Bitmap.Config.ARGB_8888);
bitmap.copyPixelsFromBuffer(buffer);
// Trim the screenshot to the correct size.
croppedBitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height);
screenshotFolder.mkdirs();
final File file =
new File(screenshotFolder, SCREENSHOT_FILE_FORMAT.format(new Date()));
out = new FileOutputStream(file);
pressFormat.PNG, 100, out);
out.flush();
if (lens != null) {
post(new Runnable() {
@Override public void run() {
lens.onCapture(file);
} catch (IOException e) {
Log.e(TAG,
&Failed to save screenshot. Is the WRITE_EXTERNAL_STORAGE permission requested?&);
} finally {
if (out != null) {
out.close();
} catch (IOException ignored) {
if (croppedBitmap != null) {
croppedBitmap.recycle();
if (bitmap != null) {
bitmap.recycle();
if (image != null) {
image.close();
reader.close();
display.release();
projection.stop();
}, getBackgroundHandler());
public TelescopeLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
setWillNotDraw(false);
screenshotTarget =
float density = context.getResources().getDisplayMetrics().
halfStrokeWidth = PROGRESS_STROKE_DP * density / 2;
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TelescopeLayout, defStyle, 0);
pointerCount = a.getInt(R.styleable.TelescopeLayout_pointerCount, DEFAULT_POINTER_COUNT);
int progressColor =
a.getColor(R.styleable.TelescopeLayout_progressColor, DEFAULT_PROGRESS_COLOR);
screenshotMode = ScreenshotMode.values()[a.getInt(R.styleable.TelescopeLayout_screenshotMode,
ScreenshotMode.SYSTEM.ordinal())];
screenshotChildrenOnly =
a.getBoolean(R.styleable.TelescopeLayout_screenshotChildrenOnly, false);
vibrate = a.getBoolean(R.styleable.TelescopeLayout_vibrate, true);
a.recycle();
progressPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
progressPaint.setColor(progressColor);
progressPaint.setStrokeWidth(PROGRESS_STROKE_DP * density);
progressPaint.setStyle(Style.STROKE);
AnimatorUpdateListener progressUpdateListener = new AnimatorUpdateListener() {
@Override public void onAnimationUpdate(ValueAnimator animation) {
progressFraction = (float) animation.getAnimatedValue();
invalidate();
progressAnimator = new ValueAnimator();
progressAnimator.setDuration(TRIGGER_DURATION_MS);
progressAnimator.addUpdateListener(progressUpdateListener);
progressCancelAnimator = new ValueAnimator();
progressCancelAnimator.setDuration(CANCEL_DURATION_MS);
progressCancelAnimator.addUpdateListener(progressUpdateListener);
doneFraction = 1;
doneAnimator = ValueAnimator.ofFloat(0, 1);
doneAnimator.setDuration(DONE_DURATION_MS);
doneAnimator.addUpdateListener(new AnimatorUpdateListener() {
@Override public void onAnimationUpdate(ValueAnimator animation) {
doneFraction = (float) animation.getAnimatedValue();
invalidate();
if (isInEditMode()) {
projectionManager =
windowManager =
vibrator =
screenshotFolder =
requestCaptureFilter =
requestCaptureReceiver =
windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
screenshotFolder = getScreenshotFolder(context);
if (SDK_INT & LOLLIPOP) {
projectionManager =
requestCaptureFilter =
requestCaptureReceiver =
projectionManager =
(MediaProjectionManager) context.getSystemService(Context.MEDIA_PROJECTION_SERVICE);
requestCaptureFilter =
new IntentFilter(RequestCaptureActivity.getResultBroadcastAction(context));
requestCaptureReceiver = new BroadcastReceiver() {
@TargetApi(Build.VERSION_CODES.LOLLIPOP) @Override
public void onReceive(Context context, Intent intent) {
unregisterRequestCaptureReceiver();
int resultCode = intent.getIntExtra(RequestCaptureActivity.RESULT_EXTRA_CODE,
Activity.RESULT_CANCELED);
Intent data = intent.getParcelableExtra(RequestCaptureActivity.RESULT_EXTRA_DATA);
final MediaProjection mediaProjection =
projectionManager.getMediaProjection(resultCode, data);
if (mediaProjection == null) {
captureCanvasScreenshot();
// Delay capture until after the permission dialog is gone.
postDelayed(new Runnable() {
@Override public void run() {
captureNativeScreenshot(mediaProjection);}

我要回帖

更多关于 android 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信