From f1fe109bfaef903e85380abb190b0efe0498177e Mon Sep 17 00:00:00 2001 From: Oliver Woodman Date: Wed, 17 Dec 2014 19:16:02 +0000 Subject: [PATCH 1/4] Fix AC3Passthrough - Handle read returning NOTHING_READ for AC-3 streams. - Remove extra checks for the audio track being initialized. - Call isInitialized() instead of checking audioTrack != null. --- .../exoplayer/Ac3PassthroughAudioTrackRenderer.java | 13 ++++--------- .../google/android/exoplayer/audio/AudioTrack.java | 12 ++++++------ 2 files changed, 10 insertions(+), 15 deletions(-) diff --git a/library/src/main/java/com/google/android/exoplayer/Ac3PassthroughAudioTrackRenderer.java b/library/src/main/java/com/google/android/exoplayer/Ac3PassthroughAudioTrackRenderer.java index 8b5b499878..932ed486b7 100644 --- a/library/src/main/java/com/google/android/exoplayer/Ac3PassthroughAudioTrackRenderer.java +++ b/library/src/main/java/com/google/android/exoplayer/Ac3PassthroughAudioTrackRenderer.java @@ -199,11 +199,9 @@ public final class Ac3PassthroughAudioTrackRenderer extends TrackRenderer { int result = source.readData(trackIndex, currentPositionUs, formatHolder, sampleHolder, false); - sampleHolder.data.flip(); - shouldReadInputBuffer = false; - if (result == SampleSource.FORMAT_READ) { format = formatHolder.format; + audioTrack.reconfigure(format.getFrameworkMediaFormatV16(), AudioFormat.ENCODING_AC3, 0); } if (result == SampleSource.END_OF_STREAM) { inputStreamEnded = true; @@ -211,6 +209,7 @@ public final class Ac3PassthroughAudioTrackRenderer extends TrackRenderer { if (result != SampleSource.SAMPLE_READ) { return; } + shouldReadInputBuffer = false; } int handleBufferResult = @@ -227,16 +226,12 @@ public final class Ac3PassthroughAudioTrackRenderer extends TrackRenderer { @Override protected void onStarted() { - if (audioTrack.isInitialized()) { - audioTrack.play(); - } + audioTrack.play(); } @Override protected void onStopped() { - if (audioTrack.isInitialized()) { - audioTrack.pause(); - } + audioTrack.pause(); } @Override diff --git a/library/src/main/java/com/google/android/exoplayer/audio/AudioTrack.java b/library/src/main/java/com/google/android/exoplayer/audio/AudioTrack.java index 2b109e79d3..52602e1483 100644 --- a/library/src/main/java/com/google/android/exoplayer/audio/AudioTrack.java +++ b/library/src/main/java/com/google/android/exoplayer/audio/AudioTrack.java @@ -310,8 +310,8 @@ public final class AudioTrack { // TODO: Does channelConfig determine channelCount? boolean isAc3 = encoding == AudioFormat.ENCODING_AC3 || encoding == AudioFormat.ENCODING_E_AC3; - if (audioTrack != null && this.sampleRate == sampleRate - && this.channelConfig == channelConfig && !this.isAc3 && !isAc3) { + if (isInitialized() && this.sampleRate == sampleRate && this.channelConfig == channelConfig + && !this.isAc3 && !isAc3) { // We already have an existing audio track with the correct sample rate and channel config. return; } @@ -450,7 +450,7 @@ public final class AudioTrack { /** Returns whether the audio track has more data pending that will be played back. */ public boolean hasPendingData() { - return audioTrack != null && bytesToFrames(submittedBytes) > getPlaybackPositionFrames(); + return isInitialized() && bytesToFrames(submittedBytes) > getPlaybackPositionFrames(); } /** Returns whether enough data has been supplied via {@link #handleBuffer} to begin playback. */ @@ -461,7 +461,7 @@ public final class AudioTrack { /** Sets the playback volume. */ public void setVolume(float volume) { this.volume = volume; - if (audioTrack != null) { + if (isInitialized()) { if (Util.SDK_INT >= 21) { setVolumeV21(audioTrack, volume); } else { @@ -482,7 +482,7 @@ public final class AudioTrack { /** Pauses playback. */ public void pause() { - if (audioTrack != null) { + if (isInitialized()) { resetSyncParams(); audioTrack.pause(); } @@ -494,7 +494,7 @@ public final class AudioTrack { * after resetting. */ public void reset() { - if (audioTrack != null) { + if (isInitialized()) { submittedBytes = 0; temporaryBufferSize = 0; lastRawPlaybackHeadPosition = 0; From 3a9d08edb58529f1c2e0a271e2422e1e5030ba7e Mon Sep 17 00:00:00 2001 From: Oliver Woodman Date: Wed, 17 Dec 2014 19:18:33 +0000 Subject: [PATCH 2/4] Misc performance/correctness tweaks. --- .../android/exoplayer/ExoPlayerImpl.java | 1 + .../google/android/exoplayer/MediaFormat.java | 2 +- .../android/exoplayer/parser/mp4/Atom.java | 4 +- .../parser/mp4/FragmentedMp4Extractor.java | 18 +++----- .../SmoothStreamingChunkSource.java | 8 ++-- .../SmoothStreamingManifest.java | 2 +- .../android/exoplayer/text/SubtitleView.java | 2 +- .../exoplayer/upstream/NetworkLock.java | 46 +++++++++++++------ .../google/android/exoplayer/util/Util.java | 16 +++---- 9 files changed, 58 insertions(+), 41 deletions(-) diff --git a/library/src/main/java/com/google/android/exoplayer/ExoPlayerImpl.java b/library/src/main/java/com/google/android/exoplayer/ExoPlayerImpl.java index 22f11c13b7..3f5dc3cb0c 100644 --- a/library/src/main/java/com/google/android/exoplayer/ExoPlayerImpl.java +++ b/library/src/main/java/com/google/android/exoplayer/ExoPlayerImpl.java @@ -53,6 +53,7 @@ import java.util.concurrent.CopyOnWriteArraySet; @SuppressLint("HandlerLeak") public ExoPlayerImpl(int rendererCount, int minBufferMs, int minRebufferMs) { Log.i(TAG, "Init " + ExoPlayerLibraryInfo.VERSION); + this.playWhenReady = false; this.playbackState = STATE_IDLE; this.listeners = new CopyOnWriteArraySet(); this.rendererEnabledFlags = new boolean[rendererCount]; diff --git a/library/src/main/java/com/google/android/exoplayer/MediaFormat.java b/library/src/main/java/com/google/android/exoplayer/MediaFormat.java index 20a45738bc..d3735ad7af 100644 --- a/library/src/main/java/com/google/android/exoplayer/MediaFormat.java +++ b/library/src/main/java/com/google/android/exoplayer/MediaFormat.java @@ -156,7 +156,7 @@ public class MediaFormat { public int hashCode() { if (hashCode == 0) { int result = 17; - result = 31 * result + mimeType == null ? 0 : mimeType.hashCode(); + result = 31 * result + (mimeType == null ? 0 : mimeType.hashCode()); result = 31 * result + maxInputSize; result = 31 * result + width; result = 31 * result + height; diff --git a/library/src/main/java/com/google/android/exoplayer/parser/mp4/Atom.java b/library/src/main/java/com/google/android/exoplayer/parser/mp4/Atom.java index 9a2341e904..36383dcea1 100644 --- a/library/src/main/java/com/google/android/exoplayer/parser/mp4/Atom.java +++ b/library/src/main/java/com/google/android/exoplayer/parser/mp4/Atom.java @@ -80,9 +80,11 @@ import java.util.ArrayList; public final static class ContainerAtom extends Atom { public final ArrayList children; + public final int endByteOffset; - public ContainerAtom(int type) { + public ContainerAtom(int type, int endByteOffset) { super(type); + this.endByteOffset = endByteOffset; children = new ArrayList(); } diff --git a/library/src/main/java/com/google/android/exoplayer/parser/mp4/FragmentedMp4Extractor.java b/library/src/main/java/com/google/android/exoplayer/parser/mp4/FragmentedMp4Extractor.java index 52fe8a94a1..599d0b0eab 100644 --- a/library/src/main/java/com/google/android/exoplayer/parser/mp4/FragmentedMp4Extractor.java +++ b/library/src/main/java/com/google/android/exoplayer/parser/mp4/FragmentedMp4Extractor.java @@ -139,7 +139,6 @@ public final class FragmentedMp4Extractor implements Extractor { private final ParsableByteArray atomHeader; private final byte[] extendedTypeScratch; private final Stack containerAtoms; - private final Stack containerAtomEndPoints; private final TrackFragment fragmentRun; private int parserState; @@ -174,7 +173,6 @@ public final class FragmentedMp4Extractor implements Extractor { atomHeader = new ParsableByteArray(ATOM_HEADER_SIZE); extendedTypeScratch = new byte[16]; containerAtoms = new Stack(); - containerAtomEndPoints = new Stack(); fragmentRun = new TrackFragment(); psshData = new HashMap(); } @@ -258,7 +256,6 @@ public final class FragmentedMp4Extractor implements Extractor { } } containerAtoms.clear(); - containerAtomEndPoints.clear(); enterState(STATE_READING_ATOM_HEADER); return true; } @@ -267,7 +264,7 @@ public final class FragmentedMp4Extractor implements Extractor { switch (state) { case STATE_READING_ATOM_HEADER: atomBytesRead = 0; - if (containerAtomEndPoints.isEmpty()) { + if (containerAtoms.isEmpty()) { rootAtomBytesRead = 0; } break; @@ -300,11 +297,12 @@ public final class FragmentedMp4Extractor implements Extractor { return 0; } - if (PARSED_ATOMS.contains(atomType)) { - if (CONTAINER_TYPES.contains(atomType)) { + Integer atomTypeInteger = atomType; // Avoids boxing atomType twice. + if (PARSED_ATOMS.contains(atomTypeInteger)) { + if (CONTAINER_TYPES.contains(atomTypeInteger)) { enterState(STATE_READING_ATOM_HEADER); - containerAtoms.add(new ContainerAtom(atomType)); - containerAtomEndPoints.add(rootAtomBytesRead + atomSize - ATOM_HEADER_SIZE); + containerAtoms.add(new ContainerAtom(atomType, + rootAtomBytesRead + atomSize - ATOM_HEADER_SIZE)); } else { atomData = new ParsableByteArray(atomSize); System.arraycopy(atomHeader.data, 0, atomData.data, 0, ATOM_HEADER_SIZE); @@ -339,9 +337,7 @@ public final class FragmentedMp4Extractor implements Extractor { results |= onLeafAtomRead(new LeafAtom(atomType, atomData)); } - while (!containerAtomEndPoints.isEmpty() - && containerAtomEndPoints.peek() == rootAtomBytesRead) { - containerAtomEndPoints.pop(); + while (!containerAtoms.isEmpty() && containerAtoms.peek().endByteOffset == rootAtomBytesRead) { results |= onContainerAtomRead(containerAtoms.pop()); } diff --git a/library/src/main/java/com/google/android/exoplayer/smoothstreaming/SmoothStreamingChunkSource.java b/library/src/main/java/com/google/android/exoplayer/smoothstreaming/SmoothStreamingChunkSource.java index 0bc36a0b8b..dfd7b9f3c1 100644 --- a/library/src/main/java/com/google/android/exoplayer/smoothstreaming/SmoothStreamingChunkSource.java +++ b/library/src/main/java/com/google/android/exoplayer/smoothstreaming/SmoothStreamingChunkSource.java @@ -343,8 +343,8 @@ public class SmoothStreamingChunkSource implements ChunkSource { TrackElement trackElement = streamElement.tracks[trackIndex]; String mimeType = trackElement.mimeType; if (streamElement.type == StreamElement.TYPE_VIDEO) { - MediaFormat format = MediaFormat.createVideoFormat(mimeType, -1, trackElement.maxWidth, - trackElement.maxHeight, Arrays.asList(trackElement.csd)); + MediaFormat format = MediaFormat.createVideoFormat(mimeType, MediaFormat.NO_VALUE, + trackElement.maxWidth, trackElement.maxHeight, Arrays.asList(trackElement.csd)); format.setMaxVideoDimensions(streamElement.maxWidth, streamElement.maxHeight); return format; } else if (streamElement.type == StreamElement.TYPE_AUDIO) { @@ -355,8 +355,8 @@ public class SmoothStreamingChunkSource implements ChunkSource { csd = Collections.singletonList(CodecSpecificDataUtil.buildAudioSpecificConfig( trackElement.sampleRate, trackElement.numChannels)); } - MediaFormat format = MediaFormat.createAudioFormat(mimeType, -1, trackElement.numChannels, - trackElement.sampleRate, csd); + MediaFormat format = MediaFormat.createAudioFormat(mimeType, MediaFormat.NO_VALUE, + trackElement.numChannels, trackElement.sampleRate, csd); return format; } else if (streamElement.type == StreamElement.TYPE_TEXT) { return MediaFormat.createFormatForMimeType(streamElement.tracks[trackIndex].mimeType); diff --git a/library/src/main/java/com/google/android/exoplayer/smoothstreaming/SmoothStreamingManifest.java b/library/src/main/java/com/google/android/exoplayer/smoothstreaming/SmoothStreamingManifest.java index 7a6a32e44a..d7e6ee1358 100644 --- a/library/src/main/java/com/google/android/exoplayer/smoothstreaming/SmoothStreamingManifest.java +++ b/library/src/main/java/com/google/android/exoplayer/smoothstreaming/SmoothStreamingManifest.java @@ -273,7 +273,7 @@ public class SmoothStreamingManifest { Assertions.checkState(chunkIndex < chunkStartTimes.size()); String chunkUrl = chunkTemplate .replace(URL_PLACEHOLDER_BITRATE, Integer.toString(tracks[track].bitrate)) - .replace(URL_PLACEHOLDER_START_TIME, Long.toString(chunkStartTimes.get(chunkIndex))); + .replace(URL_PLACEHOLDER_START_TIME, chunkStartTimes.get(chunkIndex).toString()); return Util.getMergedUri(baseUri, chunkUrl); } diff --git a/library/src/main/java/com/google/android/exoplayer/text/SubtitleView.java b/library/src/main/java/com/google/android/exoplayer/text/SubtitleView.java index 7b2ecf5494..6ff3015afa 100644 --- a/library/src/main/java/com/google/android/exoplayer/text/SubtitleView.java +++ b/library/src/main/java/com/google/android/exoplayer/text/SubtitleView.java @@ -97,7 +97,7 @@ public class SubtitleView extends View { Resources resources = getContext().getResources(); DisplayMetrics displayMetrics = resources.getDisplayMetrics(); - int twoDpInPx = Math.round((2 * displayMetrics.densityDpi) / DisplayMetrics.DENSITY_DEFAULT); + int twoDpInPx = Math.round((2f * displayMetrics.densityDpi) / DisplayMetrics.DENSITY_DEFAULT); cornerRadius = twoDpInPx; outlineWidth = twoDpInPx; shadowRadius = twoDpInPx; diff --git a/library/src/main/java/com/google/android/exoplayer/upstream/NetworkLock.java b/library/src/main/java/com/google/android/exoplayer/upstream/NetworkLock.java index 26df7db5c4..2576fff1cd 100644 --- a/library/src/main/java/com/google/android/exoplayer/upstream/NetworkLock.java +++ b/library/src/main/java/com/google/android/exoplayer/upstream/NetworkLock.java @@ -53,10 +53,17 @@ public final class NetworkLock { */ public static final int DOWNLOAD_PRIORITY = 10; + private final Object lock = new Object(); + + /** Guarded by {@link #lock}. */ private final PriorityQueue queue; + /** Guarded by {@link #lock}. */ + private int highestPriority; + private NetworkLock() { queue = new PriorityQueue(); + highestPriority = Integer.MAX_VALUE; } /** @@ -64,9 +71,11 @@ public final class NetworkLock { * * @param priority The priority of the task that would like to proceed. */ - public synchronized void proceed(int priority) throws InterruptedException { - while (queue.peek() < priority) { - wait(); + public void proceed(int priority) throws InterruptedException { + synchronized (lock) { + while (highestPriority < priority) { + lock.wait(); + } } } @@ -76,8 +85,10 @@ public final class NetworkLock { * @param priority The priority of the task that would like to proceed. * @return Whether the passed priority is allowed to proceed. */ - public synchronized boolean proceedNonBlocking(int priority) { - return queue.peek() >= priority; + public boolean proceedNonBlocking(int priority) { + synchronized (lock) { + return highestPriority >= priority; + } } /** @@ -86,10 +97,11 @@ public final class NetworkLock { * @param priority The priority of the task that would like to proceed. * @throws PriorityTooLowException If the passed priority is not high enough to proceed. */ - public synchronized void proceedOrThrow(int priority) throws PriorityTooLowException { - int highestPriority = queue.peek(); - if (highestPriority < priority) { - throw new PriorityTooLowException(priority, highestPriority); + public void proceedOrThrow(int priority) throws PriorityTooLowException { + synchronized (lock) { + if (highestPriority < priority) { + throw new PriorityTooLowException(priority, highestPriority); + } } } @@ -100,8 +112,11 @@ public final class NetworkLock { * * @param priority The priority of the task. */ - public synchronized void add(int priority) { - queue.add(priority); + public void add(int priority) { + synchronized (lock) { + queue.add(priority); + highestPriority = Math.min(highestPriority, priority); + } } /** @@ -109,9 +124,12 @@ public final class NetworkLock { * * @param priority The priority of the task. */ - public synchronized void remove(int priority) { - queue.remove(priority); - notifyAll(); + public void remove(int priority) { + synchronized (lock) { + queue.remove(priority); + highestPriority = queue.isEmpty() ? Integer.MAX_VALUE : queue.peek(); + lock.notifyAll(); + } } } diff --git a/library/src/main/java/com/google/android/exoplayer/util/Util.java b/library/src/main/java/com/google/android/exoplayer/util/Util.java index 4d51fda9b0..ae2e014f0d 100644 --- a/library/src/main/java/com/google/android/exoplayer/util/Util.java +++ b/library/src/main/java/com/google/android/exoplayer/util/Util.java @@ -317,8 +317,8 @@ public final class Util { } else if (matcher.group(9).equalsIgnoreCase("Z")) { timezoneShift = 0; } else { - timezoneShift = ((Integer.valueOf(matcher.group(12)) * 60 - + Integer.valueOf(matcher.group(13)))); + timezoneShift = ((Integer.parseInt(matcher.group(12)) * 60 + + Integer.parseInt(matcher.group(13)))); if (matcher.group(11).equals("-")) { timezoneShift *= -1; } @@ -328,12 +328,12 @@ public final class Util { dateTime.clear(); // Note: The month value is 0-based, hence the -1 on group(2) - dateTime.set(Integer.valueOf(matcher.group(1)), - Integer.valueOf(matcher.group(2)) - 1, - Integer.valueOf(matcher.group(3)), - Integer.valueOf(matcher.group(4)), - Integer.valueOf(matcher.group(5)), - Integer.valueOf(matcher.group(6))); + dateTime.set(Integer.parseInt(matcher.group(1)), + Integer.parseInt(matcher.group(2)) - 1, + Integer.parseInt(matcher.group(3)), + Integer.parseInt(matcher.group(4)), + Integer.parseInt(matcher.group(5)), + Integer.parseInt(matcher.group(6))); if (!TextUtils.isEmpty(matcher.group(8))) { final BigDecimal bd = new BigDecimal("0." + matcher.group(8)); // we care only for milliseconds, so movePointRight(3) From 48540c2ba0492b9d35272f4403b240ac43906149 Mon Sep 17 00:00:00 2001 From: Oliver Woodman Date: Wed, 17 Dec 2014 19:19:39 +0000 Subject: [PATCH 3/4] Add icon for demo app. --- demo/src/main/AndroidManifest.xml | 1 + demo/src/main/res/drawable-hdpi/ic_launcher.png | Bin 0 -> 2929 bytes demo/src/main/res/drawable-mdpi/ic_launcher.png | Bin 0 -> 1798 bytes demo/src/main/res/drawable-xhdpi/ic_launcher.png | Bin 0 -> 4177 bytes .../src/main/res/drawable-xxhdpi/ic_launcher.png | Bin 0 -> 6846 bytes .../main/res/drawable-xxxhdpi/ic_launcher.png | Bin 0 -> 9809 bytes .../src/main/res/layout/player_activity_full.xml | 7 +++++-- 7 files changed, 6 insertions(+), 2 deletions(-) create mode 100644 demo/src/main/res/drawable-hdpi/ic_launcher.png create mode 100644 demo/src/main/res/drawable-mdpi/ic_launcher.png create mode 100644 demo/src/main/res/drawable-xhdpi/ic_launcher.png create mode 100644 demo/src/main/res/drawable-xxhdpi/ic_launcher.png create mode 100644 demo/src/main/res/drawable-xxxhdpi/ic_launcher.png diff --git a/demo/src/main/AndroidManifest.xml b/demo/src/main/AndroidManifest.xml index ee2f978324..ff3821f8fb 100644 --- a/demo/src/main/AndroidManifest.xml +++ b/demo/src/main/AndroidManifest.xml @@ -29,6 +29,7 @@ diff --git a/demo/src/main/res/drawable-hdpi/ic_launcher.png b/demo/src/main/res/drawable-hdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..3e5716b8ad18f4c26bb4ceb5d53370160a6ff212 GIT binary patch literal 2929 zcmV-%3y$=OP)99J2~|IeA-y_d zfntAen$65iA!RvWLJb+FaqczZn~(hBwnih`LlH3muw;@>v8EDI%A(dp_6n&lCKQ#G zaIR&OZ*dG{8w_?18+AyQAYFz)B;#)9kH6dhqa$;3a}t1r237*(feGFHVa=oy0O)~- zesH4IY~BDczy#>FGaErcH=Qj421EaYTSxzML4gC;hVwL^-Sdq|V8i<9f9G-c_V0ad z-%Gk;(z=)fM*yIkzkPVqbvt)`sUuoD73CTZ4dh z_X4ha{W%B`87y_6P2I4XlWHO$%Ox)SZ{eDC&E}5*>;{knAU_5P0AlxdAHS-#<70n2 zm*!JB1lZh3BO-fe%MRTCT_cUI1OsTcXK;0=gZA_^NC>P|C?W!e<=g3Hw?M^a2EamP zK(0GQ*|u9Beyhh*8M|<_@v!&3-y{Pv&yjSykoht)8qr1*9}|E`Z{!XXP0WZEIJ(n7 zvC#?$x|TlN_q|l4Qv`z{WsY9l0lU$&bbUF8)n2m-WFJ8bMtJHG0HTCNn^`AxHW!Y2 z$`({Al)dk6Vg|EB5_iEYZLloYdU-7zczH1M(lMd8uz~>c*+8;wTYuaM#GX*G41k^f zoh73e$5u&xJNuMa(VK;@_4D#oi9u$2Zs8oTDl%OlvyK~%VvNg42TW<>qJQ!gXG}_` z>y?aN5&kS)CkQT@#w8@vP#hMaYsv4D)PY?x2l4pKC?5dXFzx1y*P$+ zV$#s+;jqI58m;p!Yr4)m-EQ8hs4nQb$6Upfj~Czj&goC2gElm{EJ@I4wLn_fOI42_ z)9T%;x}4x#%(znUT!rt4!1%{)y;+YYH!PwiXdNm8cJ6}2n<01w` zKO8sM=UIxYHf;>TG1vAt(hIx;6;l(Ts{r|plc?|2LQwj8J)%}V9q>WNSYVuVy5Q+n~SY$C3cVKvM2mlj-0PNav1HSr& z&*Ht;zH6CqhIg$hKz1AyYJ8tdApkLy&N&ZeJy7H_7<;Y0vpP7LrH+j=>#*;hJ8{>? zZ^cxzxlB0q;~yVTX@SgbxWD;Is)84W#=083JR&ncdK9! zm(pM;2PYVCg%a#Egvi2iA*E>wX2#}C8?f)by}19=x1l{XBW1Kh>V-`!yyM)mSt!(8XzL<-nkvy zw{F3K!$Gz?OZ~h_EZC$in~VcvlVl)^q5e)j}Q9)L0}(tp(0#e>8I5-L9sAVdTqL;=sZk>ce%y-jrelW%ra%cH zAOVQd{EBQgux@1(RS(C7WZ|!%89-{_3OzuBPz|C8?db@;B!{Ne%&nI*;zz;dIpg&YaM`9n{g{}@TDCBRKxl2 z{6*|P^bF=+`}0oMl z8bWwI7nE{}SXQMV!m$%C;8#cffH>(5Th)=x0FqD->m`7k2MZ}X5YRc%(t?H3g26ks}7Rd+( zhUyS{iGt*guZWc5o_YQ+c;eV`^s)?V2?yv0q+$@OiVbU{cq8fQOfi@wn@MVwWIHeX z@Zcewzwow6JwizIK{C%%dwV_g5w~5^IwmzR)L|#u3_M~r}BL5AcaQKGXBZ;A8IblCsD-@y_ae- z&p|?{ZAoy7Yh+&fiTg^{u{232tti6G>W@ElAx#!`wC=k9?&z9p?_ff6q*BaGSG~@I z*)(~d0GhMi&N7rkc4wZJ6i+f%ZZMgpy_ez4uSq`%AlM&~qY0p;w+$6igZ3^GwIEZxE#zb^FRqB1<-@KxtaefSNlGk z-i!){g=5SIBv6KJ)H+Uc*YOOX9D31EZ@eb2WI}=Q-E_RO(8AosLU-v|0+4I+QZEWv z=A2Q{xUIAri~^Qbco5J^nfERl0{hFsII!1Gnk!xlpIBj&|GT5cCV*;e0;t9&fNE?4 bsK)*eyQy>SBxZs*00000NkvXXu0mjf)E8>! literal 0 HcmV?d00001 diff --git a/demo/src/main/res/drawable-mdpi/ic_launcher.png b/demo/src/main/res/drawable-mdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..a5d2a53b131511f9734eba6be2b6475177dcb5ed GIT binary patch literal 1798 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 N+`FT%S*~sy`9C%i_>2Gm literal 0 HcmV?d00001 diff --git a/demo/src/main/res/drawable-xxhdpi/ic_launcher.png b/demo/src/main/res/drawable-xxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..ef2f312fd4bff190a270ba2366d3c2159bc63493 GIT binary patch literal 6846 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 literal 0 HcmV?d00001 diff --git a/demo/src/main/res/layout/player_activity_full.xml b/demo/src/main/res/layout/player_activity_full.xml index d2e069620f..21fe68e5da 100644 --- a/demo/src/main/res/layout/player_activity_full.xml +++ b/demo/src/main/res/layout/player_activity_full.xml @@ -14,6 +14,7 @@ limitations under the License. --> + android:textSize="10sp" + tools:ignore="SmallSp"/> + android:textSize="10sp" + tools:ignore="SmallSp"/> Date: Wed, 17 Dec 2014 19:22:52 +0000 Subject: [PATCH 4/4] Add launcher icon source. --- demo/assets/ic_launcher.svg | 660 ++++++++++++++++++++++++++++++++++ demo/assets/ic_launcher.svg~ | 665 +++++++++++++++++++++++++++++++++++ 2 files changed, 1325 insertions(+) create mode 100644 demo/assets/ic_launcher.svg create mode 100644 demo/assets/ic_launcher.svg~ diff --git a/demo/assets/ic_launcher.svg b/demo/assets/ic_launcher.svg new file mode 100644 index 0000000000..5486b27e29 --- /dev/null +++ b/demo/assets/ic_launcher.svg @@ -0,0 +1,660 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/demo/assets/ic_launcher.svg~ b/demo/assets/ic_launcher.svg~ new file mode 100644 index 0000000000..c01934f697 --- /dev/null +++ b/demo/assets/ic_launcher.svg~ @@ -0,0 +1,665 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +