mirror of
https://github.com/samsonjs/media.git
synced 2026-04-27 15:07:40 +00:00
Merge branch 'dev-v2' of git://github.com/geekygecko/ExoPlayer into geekygecko-dev-v2
This commit is contained in:
commit
31602af3e6
4 changed files with 434 additions and 2 deletions
|
|
@ -0,0 +1,125 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2017 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.google.android.exoplayer2.metadata.id3;
|
||||||
|
|
||||||
|
import android.os.Parcel;
|
||||||
|
|
||||||
|
import com.google.android.exoplayer2.util.Util;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Chapter information "CHAP" ID3 frame.
|
||||||
|
*/
|
||||||
|
public final class ChapFrame extends Id3Frame {
|
||||||
|
|
||||||
|
public static final String ID = "CHAP";
|
||||||
|
|
||||||
|
public final String chapterId;
|
||||||
|
public final int startTime;
|
||||||
|
public final int endTime;
|
||||||
|
public final int startOffset;
|
||||||
|
public final int endOffset;
|
||||||
|
public final String title;
|
||||||
|
public final String url;
|
||||||
|
public final ApicFrame image;
|
||||||
|
|
||||||
|
public ChapFrame(String chapterId, int startTime, int endTime, int startOffset, int endOffset,
|
||||||
|
String title, String url, ApicFrame image) {
|
||||||
|
super(ID);
|
||||||
|
this.chapterId = chapterId;
|
||||||
|
this.startTime = startTime;
|
||||||
|
this.endTime = endTime;
|
||||||
|
this.startOffset = startOffset;
|
||||||
|
this.endOffset = endOffset;
|
||||||
|
this.title = title;
|
||||||
|
this.url = url;
|
||||||
|
this.image = image;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* package */ ChapFrame(Parcel in) {
|
||||||
|
super(ID);
|
||||||
|
this.chapterId = in.readString();
|
||||||
|
this.startTime = in.readInt();
|
||||||
|
this.endTime = in.readInt();
|
||||||
|
this.startOffset = in.readInt();
|
||||||
|
this.endOffset = in.readInt();
|
||||||
|
this.title = in.readString();
|
||||||
|
this.url = in.readString();
|
||||||
|
this.image = in.readParcelable(ApicFrame.class.getClassLoader());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (obj == null || getClass() != obj.getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ChapFrame other = (ChapFrame) obj;
|
||||||
|
return startTime == other.startTime
|
||||||
|
&& endTime == other.endTime
|
||||||
|
&& startOffset == other.startOffset
|
||||||
|
&& endOffset == other.endOffset
|
||||||
|
&& Util.areEqual(chapterId, other.chapterId)
|
||||||
|
&& Util.areEqual(title, other.title)
|
||||||
|
&& Util.areEqual(url, other.url)
|
||||||
|
&& Util.areEqual(image, other.image);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
int result = 17;
|
||||||
|
result = 31 * result + (chapterId != null ? chapterId.hashCode() : 0);
|
||||||
|
result = 31 * result + startTime;
|
||||||
|
result = 31 * result + endTime;
|
||||||
|
result = 31 * result + startOffset;
|
||||||
|
result = 31 * result + endOffset;
|
||||||
|
result = 31 * result + (title != null ? title.hashCode() : 0);
|
||||||
|
result = 31 * result + (url != null ? url.hashCode() : 0);
|
||||||
|
result = 31 * result + (image != null ? image.hashCode() : 0);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeToParcel(Parcel dest, int flags) {
|
||||||
|
dest.writeString(chapterId);
|
||||||
|
dest.writeInt(startTime);
|
||||||
|
dest.writeInt(endTime);
|
||||||
|
dest.writeInt(startOffset);
|
||||||
|
dest.writeInt(endOffset);
|
||||||
|
dest.writeString(title);
|
||||||
|
dest.writeString(url);
|
||||||
|
dest.writeString(title);
|
||||||
|
dest.writeParcelable(image, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int describeContents() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final Creator<ChapFrame> CREATOR = new Creator<ChapFrame>() {
|
||||||
|
@Override
|
||||||
|
public ChapFrame createFromParcel(Parcel in) {
|
||||||
|
return new ChapFrame(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ChapFrame[] newArray(int size) {
|
||||||
|
return new ChapFrame[size];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,102 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2017 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.google.android.exoplayer2.metadata.id3;
|
||||||
|
|
||||||
|
import android.os.Parcel;
|
||||||
|
|
||||||
|
import com.google.android.exoplayer2.util.Util;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Chapter table of contents information "CTOC" ID3 frame.
|
||||||
|
*/
|
||||||
|
public final class CtocFrame extends Id3Frame {
|
||||||
|
|
||||||
|
public static final String ID = "CTOC";
|
||||||
|
|
||||||
|
public final String elementId;
|
||||||
|
public final boolean isRoot;
|
||||||
|
public final boolean isOrdered;
|
||||||
|
public final String[] children;
|
||||||
|
public final String title;
|
||||||
|
|
||||||
|
public CtocFrame(String elementId, boolean isRoot, boolean isOrdered, String[] children, String title) {
|
||||||
|
super(ID);
|
||||||
|
this.elementId = elementId;
|
||||||
|
this.isRoot = isRoot;
|
||||||
|
this.isOrdered = isOrdered;
|
||||||
|
this.children = children;
|
||||||
|
this.title = title;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* package */ CtocFrame(Parcel in) {
|
||||||
|
super(ID);
|
||||||
|
this.elementId = in.readString();
|
||||||
|
this.isRoot = in.readByte() != 0;
|
||||||
|
this.isOrdered = in.readByte() != 0;
|
||||||
|
this.children = in.createStringArray();
|
||||||
|
this.title = in.readString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (obj == null || getClass() != obj.getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
CtocFrame other = (CtocFrame) obj;
|
||||||
|
return isRoot == other.isRoot
|
||||||
|
&& isOrdered == other.isOrdered
|
||||||
|
&& Util.areEqual(elementId, other.elementId)
|
||||||
|
&& Util.areEqual(title, other.title)
|
||||||
|
&& Arrays.equals(children, other.children);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
int result = 17;
|
||||||
|
result = 31 * result + (elementId != null ? elementId.hashCode() : 0);
|
||||||
|
result = 31 * result + (isRoot ? 1 : 0);
|
||||||
|
result = 31 * result + (isOrdered ? 1 : 0);
|
||||||
|
result = 31 * result + Arrays.hashCode(children);
|
||||||
|
result = 31 * result + (title != null ? title.hashCode() : 0);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeToParcel(Parcel dest, int flags) {
|
||||||
|
dest.writeString(elementId);
|
||||||
|
dest.writeByte((byte)(isRoot ? 1 : 0));
|
||||||
|
dest.writeByte((byte)(isOrdered ? 1 : 0));
|
||||||
|
dest.writeStringArray(children);
|
||||||
|
dest.writeString(title);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final Creator<CtocFrame> CREATOR = new Creator<CtocFrame>() {
|
||||||
|
@Override
|
||||||
|
public CtocFrame createFromParcel(Parcel in) {
|
||||||
|
return new CtocFrame(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CtocFrame[] newArray(int size) {
|
||||||
|
return new CtocFrame[size];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
@ -98,7 +98,7 @@ public final class Id3Decoder implements MetadataDecoder {
|
||||||
|
|
||||||
int frameHeaderSize = id3Header.majorVersion == 2 ? 6 : 10;
|
int frameHeaderSize = id3Header.majorVersion == 2 ? 6 : 10;
|
||||||
while (id3Data.bytesLeft() >= frameHeaderSize) {
|
while (id3Data.bytesLeft() >= frameHeaderSize) {
|
||||||
Id3Frame frame = decodeFrame(id3Header.majorVersion, id3Data, unsignedIntFrameSizeHack);
|
Id3Frame frame = decodeFrame(id3Header.majorVersion, id3Data, unsignedIntFrameSizeHack, frameHeaderSize);
|
||||||
if (frame != null) {
|
if (frame != null) {
|
||||||
id3Frames.add(frame);
|
id3Frames.add(frame);
|
||||||
}
|
}
|
||||||
|
|
@ -204,7 +204,7 @@ public final class Id3Decoder implements MetadataDecoder {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Id3Frame decodeFrame(int majorVersion, ParsableByteArray id3Data,
|
private static Id3Frame decodeFrame(int majorVersion, ParsableByteArray id3Data,
|
||||||
boolean unsignedIntFrameSizeHack) {
|
boolean unsignedIntFrameSizeHack, int frameHeaderSize) {
|
||||||
int frameId0 = id3Data.readUnsignedByte();
|
int frameId0 = id3Data.readUnsignedByte();
|
||||||
int frameId1 = id3Data.readUnsignedByte();
|
int frameId1 = id3Data.readUnsignedByte();
|
||||||
int frameId2 = id3Data.readUnsignedByte();
|
int frameId2 = id3Data.readUnsignedByte();
|
||||||
|
|
@ -296,6 +296,15 @@ public final class Id3Decoder implements MetadataDecoder {
|
||||||
} else if (frameId0 == 'C' && frameId1 == 'O' && frameId2 == 'M'
|
} else if (frameId0 == 'C' && frameId1 == 'O' && frameId2 == 'M'
|
||||||
&& (frameId3 == 'M' || majorVersion == 2)) {
|
&& (frameId3 == 'M' || majorVersion == 2)) {
|
||||||
frame = decodeCommentFrame(id3Data, frameSize);
|
frame = decodeCommentFrame(id3Data, frameSize);
|
||||||
|
} else if (majorVersion == 2 ? (frameId0 == 'W' && frameId1 == 'X' && frameId2 == 'X')
|
||||||
|
: (frameId0 == 'W' && frameId1 == 'X' && frameId2 == 'X' && frameId3 == 'X')) {
|
||||||
|
frame = decodeWxxxFrame(id3Data, frameSize);
|
||||||
|
} else if (frameId0 == 'C' && frameId1 == 'H' && frameId2 == 'A' && frameId3 == 'P') {
|
||||||
|
frame = decodeChapFrame(id3Data, frameSize, majorVersion, unsignedIntFrameSizeHack,
|
||||||
|
frameHeaderSize);
|
||||||
|
} else if (frameId0 == 'C' && frameId1 == 'T' && frameId2 == 'O' && frameId3 == 'C') {
|
||||||
|
frame = decodeCtocFrame(id3Data, frameSize, majorVersion, unsignedIntFrameSizeHack,
|
||||||
|
frameHeaderSize);
|
||||||
} else {
|
} else {
|
||||||
String id = majorVersion == 2
|
String id = majorVersion == 2
|
||||||
? String.format(Locale.US, "%c%c%c", frameId0, frameId1, frameId2)
|
? String.format(Locale.US, "%c%c%c", frameId0, frameId1, frameId2)
|
||||||
|
|
@ -458,6 +467,115 @@ public final class Id3Decoder implements MetadataDecoder {
|
||||||
return new TextInformationFrame(id, description);
|
return new TextInformationFrame(id, description);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static WxxxFrame decodeWxxxFrame(ParsableByteArray id3Data,
|
||||||
|
int frameSize) throws UnsupportedEncodingException {
|
||||||
|
int encoding = id3Data.readUnsignedByte();
|
||||||
|
String charset = getCharsetName(encoding);
|
||||||
|
|
||||||
|
byte[] data = new byte[frameSize - 1];
|
||||||
|
id3Data.readBytes(data, 0, frameSize - 1);
|
||||||
|
|
||||||
|
int descriptionEndIndex = indexOfEos(data, 0, encoding);
|
||||||
|
String description = new String(data, 0, descriptionEndIndex, charset);
|
||||||
|
|
||||||
|
String url;
|
||||||
|
int urlStartIndex = descriptionEndIndex + delimiterLength(encoding);
|
||||||
|
if (urlStartIndex < data.length) {
|
||||||
|
int urlEndIndex = indexOfEos(data, urlStartIndex, encoding);
|
||||||
|
url = new String(data, urlStartIndex, urlEndIndex - urlStartIndex, charset);
|
||||||
|
} else {
|
||||||
|
url = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
return new WxxxFrame(description, url);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ChapFrame decodeChapFrame(ParsableByteArray id3Data, int frameSize,
|
||||||
|
int majorVersion, boolean unsignedIntFrameSizeHack, int frameHeaderSize)
|
||||||
|
throws UnsupportedEncodingException {
|
||||||
|
byte[] frameBytes = new byte[frameSize];
|
||||||
|
id3Data.readBytes(frameBytes, 0, frameSize - 1);
|
||||||
|
|
||||||
|
ParsableByteArray chapterData = new ParsableByteArray(frameBytes);
|
||||||
|
|
||||||
|
int chapterIdEndIndex = indexOfZeroByte(frameBytes, 0) + 1;
|
||||||
|
String chapterId = chapterData.readNullTerminatedString(chapterIdEndIndex);
|
||||||
|
|
||||||
|
chapterData.setPosition(chapterIdEndIndex);
|
||||||
|
int startTime = chapterData.readInt();
|
||||||
|
int endTime = chapterData.readInt();
|
||||||
|
int startOffset = chapterData.readInt();
|
||||||
|
int endOffset = chapterData.readInt();
|
||||||
|
|
||||||
|
String title = null;
|
||||||
|
String url = null;
|
||||||
|
ApicFrame image = null;
|
||||||
|
|
||||||
|
while (chapterData.bytesLeft() >= frameHeaderSize) {
|
||||||
|
Id3Frame frame = decodeFrame(majorVersion, chapterData, unsignedIntFrameSizeHack,
|
||||||
|
frameHeaderSize);
|
||||||
|
if (frame == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (frame instanceof TextInformationFrame) {
|
||||||
|
TextInformationFrame textFrame = (TextInformationFrame)frame;
|
||||||
|
if ("TIT2".equals(textFrame.id)) {
|
||||||
|
title = textFrame.description;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (frame instanceof WxxxFrame) {
|
||||||
|
WxxxFrame linkFrame = (WxxxFrame)frame;
|
||||||
|
url = linkFrame.url;
|
||||||
|
}
|
||||||
|
else if (frame instanceof ApicFrame) {
|
||||||
|
image = (ApicFrame)frame;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ChapFrame(chapterId, startTime, endTime, startOffset, endOffset, title, url, image);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static CtocFrame decodeCtocFrame(ParsableByteArray id3Data, int frameSize,
|
||||||
|
int majorVersion, boolean unsignedIntFrameSizeHack, int frameHeaderSize)
|
||||||
|
throws UnsupportedEncodingException {
|
||||||
|
byte[] frameBytes = new byte[frameSize];
|
||||||
|
id3Data.readBytes(frameBytes, 0, frameSize - 1);
|
||||||
|
|
||||||
|
ParsableByteArray tocData = new ParsableByteArray(frameBytes);
|
||||||
|
|
||||||
|
int idEndIndex = indexOfZeroByte(frameBytes, 0) + 1;
|
||||||
|
String id = tocData.readNullTerminatedString(idEndIndex);
|
||||||
|
tocData.setPosition(idEndIndex);
|
||||||
|
|
||||||
|
int flags = tocData.readUnsignedByte();
|
||||||
|
boolean isRoot = (flags & 0x0002) != 0;
|
||||||
|
boolean isOrdered = (flags & 0x0001) != 0;
|
||||||
|
|
||||||
|
int entryCount = tocData.readUnsignedByte();
|
||||||
|
String[] children = new String[entryCount];
|
||||||
|
for (int i = 0; i < entryCount; i++) {
|
||||||
|
int startIndex = tocData.getPosition();
|
||||||
|
int endIndex = indexOfZeroByte(frameBytes, startIndex) + 1;
|
||||||
|
int stringLength = endIndex - startIndex;
|
||||||
|
String childId = tocData.readNullTerminatedString(stringLength);
|
||||||
|
children[i] = childId;
|
||||||
|
}
|
||||||
|
|
||||||
|
String title = null;
|
||||||
|
while (tocData.bytesLeft() >= frameHeaderSize) {
|
||||||
|
Id3Frame frame = decodeFrame(majorVersion, tocData, unsignedIntFrameSizeHack,
|
||||||
|
frameHeaderSize);
|
||||||
|
if (frame instanceof TextInformationFrame) {
|
||||||
|
TextInformationFrame textFrame = (TextInformationFrame)frame;
|
||||||
|
if ("TIT2".equals(textFrame.id)) {
|
||||||
|
title = textFrame.description;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new CtocFrame(id, isRoot, isOrdered, children, title);
|
||||||
|
}
|
||||||
|
|
||||||
private static BinaryFrame decodeBinaryFrame(ParsableByteArray id3Data, int frameSize,
|
private static BinaryFrame decodeBinaryFrame(ParsableByteArray id3Data, int frameSize,
|
||||||
String id) {
|
String id) {
|
||||||
byte[] frame = new byte[frameSize];
|
byte[] frame = new byte[frameSize];
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,87 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2017 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.google.android.exoplayer2.metadata.id3;
|
||||||
|
|
||||||
|
import android.os.Parcel;
|
||||||
|
import android.os.Parcelable;
|
||||||
|
|
||||||
|
import com.google.android.exoplayer2.util.Util;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Url Frame "WXX" ID3 frame.
|
||||||
|
*/
|
||||||
|
public final class WxxxFrame extends Id3Frame {
|
||||||
|
|
||||||
|
public static final String ID = "WXXX";
|
||||||
|
|
||||||
|
public final String description;
|
||||||
|
public final String url;
|
||||||
|
|
||||||
|
public WxxxFrame(String description, String url) {
|
||||||
|
super(ID);
|
||||||
|
this.description = description;
|
||||||
|
this.url = url;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* package */ WxxxFrame(Parcel in) {
|
||||||
|
super(ID);
|
||||||
|
description = in.readString();
|
||||||
|
url = in.readString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (obj == null || getClass() != obj.getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
WxxxFrame other = (WxxxFrame) obj;
|
||||||
|
return Util.areEqual(description, other.description)
|
||||||
|
&& Util.areEqual(url, other.url);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
int result = 17;
|
||||||
|
result = 31 * result + (description != null ? description.hashCode() : 0);
|
||||||
|
result = 31 * result + (url != null ? url.hashCode() : 0);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeToParcel(Parcel dest, int flags) {
|
||||||
|
dest.writeString(description);
|
||||||
|
dest.writeString(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final Parcelable.Creator<WxxxFrame> CREATOR =
|
||||||
|
new Parcelable.Creator<WxxxFrame>() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WxxxFrame createFromParcel(Parcel in) {
|
||||||
|
return new WxxxFrame(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WxxxFrame[] newArray(int size) {
|
||||||
|
return new WxxxFrame[size];
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue